cubicweb/__init__.py
changeset 11417 5e5e224239c3
parent 11281 2cb8b383a519
child 11457 d404fd8499dd
equal deleted inserted replaced
11416:9c2fbb872e91 11417:5e5e224239c3
     1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     1 # copyright 2003-2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     3 #
     3 #
     4 # This file is part of CubicWeb.
     4 # This file is part of CubicWeb.
     5 #
     5 #
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
    57 # breaks later imports
    57 # breaks later imports
    58 __path__[0] = os.path.abspath(__path__[0])
    58 __path__[0] = os.path.abspath(__path__[0])
    59 CW_SOFTWARE_ROOT = __path__[0]
    59 CW_SOFTWARE_ROOT = __path__[0]
    60 
    60 
    61 
    61 
    62 from cubicweb.__pkginfo__ import version as __version__
    62 from cubicweb.__pkginfo__ import version as __version__   # noqa
    63 
    63 
    64 
    64 
    65 set_log_methods(sys.modules[__name__], logging.getLogger('cubicweb'))
    65 set_log_methods(sys.modules[__name__], logging.getLogger('cubicweb'))
    66 
    66 
    67 # make all exceptions accessible from the package
    67 # make all exceptions accessible from the package
    68 from cubicweb._exceptions import *
    68 from cubicweb._exceptions import *  # noqa
    69 from logilab.common.registry import ObjectNotFound, NoSelectableObject, RegistryNotFound
    69 from logilab.common.registry import ObjectNotFound, NoSelectableObject, RegistryNotFound  # noqa
    70 
    70 
    71 
    71 
    72 # '_' is available to mark internationalized string but should not be used to
    72 # '_' is available to mark internationalized string but should not be used to
    73 # do the actual translation
    73 # do the actual translation
    74 _ = text_type
    74 _ = text_type
    79 # convert eid to the right type, raise ValueError if it's not a valid eid
    79 # convert eid to the right type, raise ValueError if it's not a valid eid
    80 @deprecated('[3.17] typed_eid() was removed. replace it with int() when needed.')
    80 @deprecated('[3.17] typed_eid() was removed. replace it with int() when needed.')
    81 def typed_eid(eid):
    81 def typed_eid(eid):
    82     return int(eid)
    82     return int(eid)
    83 
    83 
    84 #def log_thread(f, w, a):
       
    85 #    print f.f_code.co_filename, f.f_code.co_name
       
    86 #import threading
       
    87 #threading.settrace(log_thread)
       
    88 
    84 
    89 class Binary(BytesIO):
    85 class Binary(BytesIO):
    90     """class to hold binary data. Use BytesIO to prevent use of unicode data"""
    86     """class to hold binary data. Use BytesIO to prevent use of unicode data"""
    91     _allowed_types = (binary_type, bytearray, buffer if PY2 else memoryview)
    87     _allowed_types = (binary_type, bytearray, buffer if PY2 else memoryview)
    92 
    88 
    93     def __init__(self, buf=b''):
    89     def __init__(self, buf=b''):
    94         assert isinstance(buf, self._allowed_types), \
    90         assert isinstance(buf, self._allowed_types), \
    95                "Binary objects must use bytes/buffer objects, not %s" % buf.__class__
    91             "Binary objects must use bytes/buffer objects, not %s" % buf.__class__
    96         # don't call super, BytesIO may be an old-style class (on python < 2.7.4)
    92         # don't call super, BytesIO may be an old-style class (on python < 2.7.4)
    97         BytesIO.__init__(self, buf)
    93         BytesIO.__init__(self, buf)
    98 
    94 
    99     def write(self, data):
    95     def write(self, data):
   100         assert isinstance(data, self._allowed_types), \
    96         assert isinstance(data, self._allowed_types), \
   101                "Binary objects must use bytes/buffer objects, not %s" % data.__class__
    97             "Binary objects must use bytes/buffer objects, not %s" % data.__class__
   102         # don't call super, BytesIO may be an old-style class (on python < 2.7.4)
    98         # don't call super, BytesIO may be an old-style class (on python < 2.7.4)
   103         BytesIO.write(self, data)
    99         BytesIO.write(self, data)
   104 
   100 
   105     def to_file(self, fobj):
   101     def to_file(self, fobj):
   106         """write a binary to disk
   102         """write a binary to disk
   112         self.seek(0)
   108         self.seek(0)
   113         if sys.platform == 'win32':
   109         if sys.platform == 'win32':
   114             while True:
   110             while True:
   115                 # the 16kB chunksize comes from the shutil module
   111                 # the 16kB chunksize comes from the shutil module
   116                 # in stdlib
   112                 # in stdlib
   117                 chunk = self.read(16*1024)
   113                 chunk = self.read(16 * 1024)
   118                 if not chunk:
   114                 if not chunk:
   119                     break
   115                     break
   120                 fobj.write(chunk)
   116                 fobj.write(chunk)
   121         else:
   117         else:
   122             fobj.write(self.read())
   118             fobj.write(self.read())
   133         with open(filename, 'rb') as fobj:
   129         with open(filename, 'rb') as fobj:
   134             if sys.platform == 'win32':
   130             if sys.platform == 'win32':
   135                 while True:
   131                 while True:
   136                     # the 16kB chunksize comes from the shutil module
   132                     # the 16kB chunksize comes from the shutil module
   137                     # in stdlib
   133                     # in stdlib
   138                     chunk = fobj.read(16*1024)
   134                     chunk = fobj.read(16 * 1024)
   139                     if not chunk:
   135                     if not chunk:
   140                         break
   136                         break
   141                     binary.write(chunk)
   137                     binary.write(chunk)
   142             else:
   138             else:
   143                 binary.write(fobj.read())
   139                 binary.write(fobj.read())
   147     def __eq__(self, other):
   143     def __eq__(self, other):
   148         if not isinstance(other, Binary):
   144         if not isinstance(other, Binary):
   149             return False
   145             return False
   150         return self.getvalue() == other.getvalue()
   146         return self.getvalue() == other.getvalue()
   151 
   147 
   152 
       
   153     # Binary helpers to store/fetch python objects
   148     # Binary helpers to store/fetch python objects
   154 
   149 
   155     @classmethod
   150     @classmethod
   156     def zpickle(cls, obj):
   151     def zpickle(cls, obj):
   157         """ return a Binary containing a gzipped pickle of obj """
   152         """ return a Binary containing a gzipped pickle of obj """
   166 
   161 
   167 def check_password(eschema, value):
   162 def check_password(eschema, value):
   168     return isinstance(value, (binary_type, Binary))
   163     return isinstance(value, (binary_type, Binary))
   169 BASE_CHECKERS['Password'] = check_password
   164 BASE_CHECKERS['Password'] = check_password
   170 
   165 
       
   166 
   171 def str_or_binary(value):
   167 def str_or_binary(value):
   172     if isinstance(value, Binary):
   168     if isinstance(value, Binary):
   173         return value
   169         return value
   174     return binary_type(value)
   170     return binary_type(value)
   175 BASE_CONVERTERS['Password'] = str_or_binary
   171 BASE_CONVERTERS['Password'] = str_or_binary
   180 
   176 
   181 # XXX cubic web cube migration map. See if it's worth keeping this mecanism
   177 # XXX cubic web cube migration map. See if it's worth keeping this mecanism
   182 #     to help in cube renaming
   178 #     to help in cube renaming
   183 CW_MIGRATION_MAP = {}
   179 CW_MIGRATION_MAP = {}
   184 
   180 
       
   181 
   185 def neg_role(role):
   182 def neg_role(role):
   186     if role == 'subject':
   183     if role == 'subject':
   187         return 'object'
   184         return 'object'
   188     return 'subject'
   185     return 'subject'
       
   186 
   189 
   187 
   190 def role(obj):
   188 def role(obj):
   191     try:
   189     try:
   192         return obj.role
   190         return obj.role
   193     except AttributeError:
   191     except AttributeError:
   194         return neg_role(obj.target)
   192         return neg_role(obj.target)
   195 
   193 
       
   194 
   196 def target(obj):
   195 def target(obj):
   197     try:
   196     try:
   198         return obj.target
   197         return obj.target
   199     except AttributeError:
   198     except AttributeError:
   200         return neg_role(obj.role)
   199         return neg_role(obj.role)
   218     """
   217     """
   219     def __init__(self):
   218     def __init__(self):
   220         self.callbacks = {}
   219         self.callbacks = {}
   221 
   220 
   222     def bind(self, event, callback, *args, **kwargs):
   221     def bind(self, event, callback, *args, **kwargs):
   223         self.callbacks.setdefault(event, []).append( (callback, args, kwargs) )
   222         self.callbacks.setdefault(event, []).append((callback, args, kwargs))
   224 
   223 
   225     def emit(self, event, context=None):
   224     def emit(self, event, context=None):
   226         for callback, args, kwargs in self.callbacks.get(event, ()):
   225         for callback, args, kwargs in self.callbacks.get(event, ()):
   227             if context is None:
   226             if context is None:
   228                 callback(*args, **kwargs)
   227                 callback(*args, **kwargs)
   229             else:
   228             else:
   230                 callback(context, *args, **kwargs)
   229                 callback(context, *args, **kwargs)
   231 
   230 
   232 CW_EVENT_MANAGER = CubicWebEventManager()
   231 CW_EVENT_MANAGER = CubicWebEventManager()
   233 
   232 
       
   233 
   234 def onevent(event, *args, **kwargs):
   234 def onevent(event, *args, **kwargs):
   235     """decorator to ease event / callback binding
   235     """decorator to ease event / callback binding
   236 
   236 
   237     >>> from cubicweb import onevent
   237     >>> from cubicweb import onevent
   238     >>> @onevent('before-registry-reload')
   238     >>> @onevent('before-registry-reload')
   246         return func
   246         return func
   247     return _decorator
   247     return _decorator
   248 
   248 
   249 
   249 
   250 from yams.schema import role_name as rname
   250 from yams.schema import role_name as rname
       
   251 
   251 
   252 
   252 def validation_error(entity, errors, substitutions=None, i18nvalues=None):
   253 def validation_error(entity, errors, substitutions=None, i18nvalues=None):
   253     """easy way to retrieve a :class:`cubicweb.ValidationError` for an entity or eid.
   254     """easy way to retrieve a :class:`cubicweb.ValidationError` for an entity or eid.
   254 
   255 
   255     You may also have 2-tuple as error keys, :func:`yams.role_name` will be
   256     You may also have 2-tuple as error keys, :func:`yams.role_name` will be
   270                            substitutions, i18nvalues)
   271                            substitutions, i18nvalues)
   271 
   272 
   272 
   273 
   273 # exceptions ##################################################################
   274 # exceptions ##################################################################
   274 
   275 
   275 class ProgrammingError(Exception): #DatabaseError):
   276 class ProgrammingError(Exception):
   276     """Exception raised for errors that are related to the database's operation
   277     """Exception raised for errors that are related to the database's operation
   277     and not necessarily under the control of the programmer, e.g. an unexpected
   278     and not necessarily under the control of the programmer, e.g. an unexpected
   278     disconnect occurs, the data source name is not found, a transaction could
   279     disconnect occurs, the data source name is not found, a transaction could
   279     not be processed, a memory allocation error occurred during processing,
   280     not be processed, a memory allocation error occurred during processing,
   280     etc.
   281     etc.