[F] views: fix 2 unicode errors
1. You can now use valid unicode strings in ValidationError exception.
Previously, if 'err' contains unicode, UnicodeDecodeError was raised by format_errors()
>>> templstr = '<li>%s</li>\n'
>>> e = ValidationError(None, {None: u'oué, une exception en unicode!'})
>>> templstr % e
'<li>None (None): ou\xc3\xa9, une exception en unicode!</li>\n'
>>> templstr = u'<li>%s</li>\n'
>>> templstr % e
u'<li>None (None): ou\xe9, une exception en unicode!</li>\n'
2. The message of an Exception can contains unicode. But it now properly managed by “informal” string representation.
We can easily fix the problem by using the Exception.message attribute that still contains the original message.
>>> a = AssertionError(u'séfdsdf')
>>> a.message
u's\xe9fdsdf'
>>> str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128)
>>> a = ValueError(u'fsdfsdéfsdfs')
>>> str(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128)
>>> a
ValueError(u'fsdfsd\xe9fsdfs',)
>>> unicode(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128)
>>> a.message
u'fsdfsd\xe9fsdfs'
"""custom storages for the system source"""fromosimportunlink,pathasospfromcubicwebimportBinaryfromcubicweb.server.hookimportOperationETYPE_ATTR_STORAGE={}defset_attribute_storage(repo,etype,attr,storage):ETYPE_ATTR_STORAGE.setdefault(etype,{})[attr]=storagerepo.system_source.map_attribute(etype,attr,storage.sqlgen_callback)defunset_attribute_storage(repo,etype,attr):ETYPE_ATTR_STORAGE.setdefault(etype,{}).pop(attr,None)repo.system_source.unmap_attribute(etype,attr)classStorage(object):"""abstract storage"""defsqlgen_callback(self,generator,relation,linkedvar):"""sql generator callback when some attribute with a custom storage is accessed """raiseNotImplementedError()defentity_added(self,entity,attr):"""an entity using this storage for attr has been added"""raiseNotImplementedError()defentity_updated(self,entity,attr):"""an entity using this storage for attr has been updatded"""raiseNotImplementedError()defentity_deleted(self,entity,attr):"""an entity using this storage for attr has been deleted"""raiseNotImplementedError()# TODO# * make it configurable without code# * better file path attribution# * handle backup/restoreclassBytesFileSystemStorage(Storage):"""store Bytes attribute value on the file system"""def__init__(self,defaultdir):self.default_directory=defaultdirdefsqlgen_callback(self,generator,linkedvar,relation):"""sql generator callback when some attribute with a custom storage is accessed """linkedvar.accept(generator)return'_fsopen(%s.cw_%s)'%(linkedvar._q_sql.split('.',1)[0],# table namerelation.r_type)# attribute namedefentity_added(self,entity,attr):"""an entity using this storage for attr has been added"""ifnotentity._cw.transaction_data.get('fs_importing'):try:value=entity.pop(attr)exceptKeyError:passelse:fpath=self.new_fs_path(entity,attr)# bytes storage used to store file's pathentity[attr]=Binary(fpath)file(fpath,'w').write(value.getvalue())AddFileOp(entity._cw,filepath=fpath)# else entity[attr] is expected to be an already existant file pathdefentity_updated(self,entity,attr):"""an entity using this storage for attr has been updatded"""try:value=entity.pop(attr)exceptKeyError:passelse:fpath=self.current_fs_path(entity,attr)UpdateFileOp(entity._cw,filepath=fpath,filedata=value.getvalue())defentity_deleted(self,entity,attr):"""an entity using this storage for attr has been deleted"""DeleteFileOp(entity._cw,filepath=self.current_fs_path(entity,attr))defnew_fs_path(self,entity,attr):fspath=osp.join(self.default_directory,'%s_%s'%(entity.eid,attr))whileosp.exists(fspath):fspath='_'+fspathreturnfspathdefcurrent_fs_path(self,entity,attr):sysource=entity._cw.pool.source('system')cu=sysource.doexec(entity._cw,'SELECT cw_%s FROM cw_%s WHERE cw_eid=%s'%(attr,entity.__regid__,entity.eid))dbmod=sysource.dbapi_modulereturndbmod.process_value(cu.fetchone()[0],[None,dbmod.BINARY],binarywrap=str)classAddFileOp(Operation):defrollback_event(self):try:unlink(self.filepath)except:passclassDeleteFileOp(Operation):defcommit_event(self):try:unlink(self.filepath)except:passclassUpdateFileOp(Operation):defprecommit_event(self):try:file(self.filepath,'w').write(self.filedata)exceptException,ex:self.exception(str(ex))