dbapi.py
changeset 2650 18aec79ec3a3
parent 2496 fbd1fd2ca312
child 2657 de974465d381
equal deleted inserted replaced
2649:5d4a943695d1 2650:18aec79ec3a3
    14 from logging import getLogger
    14 from logging import getLogger
    15 from time import time, clock
    15 from time import time, clock
    16 from itertools import count
    16 from itertools import count
    17 
    17 
    18 from logilab.common.logging_ext import set_log_methods
    18 from logilab.common.logging_ext import set_log_methods
       
    19 from logilab.common.decorators import monkeypatch
       
    20 
    19 from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn
    21 from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn
    20 from cubicweb.cwvreg import CubicWebRegistry, MulCnxCubicWebRegistry
    22 from cubicweb import cwvreg, cwconfig
    21 from cubicweb.cwconfig import CubicWebNoAppConfiguration
       
    22 
    23 
    23 _MARKER = object()
    24 _MARKER = object()
    24 
    25 
    25 def _fake_property_value(self, name):
    26 def _fake_property_value(self, name):
    26     try:
    27     try:
    27         return super(dbapi.DBAPIRequest, self).property_value(name)
    28         return super(dbapi.DBAPIRequest, self).property_value(name)
    28     except KeyError:
    29     except KeyError:
    29         return ''
    30         return ''
       
    31 
       
    32 def _fix_cls_attrs(reg, vobject):
       
    33     vobject.vreg = reg.vreg
       
    34     vobject.schema = reg.schema
       
    35     vobject.config = reg.config
       
    36 
       
    37 def multiple_connections_fix():
       
    38     """some monkey patching necessary when an application has to deal with
       
    39     several connections to different repositories. It tries to hide buggy class
       
    40     attributes since classes are not designed to be shared among multiple
       
    41     registries.
       
    42     """
       
    43     defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
       
    44     orig_select_best = defaultcls.orig_select_best = defaultcls.select_best
       
    45     @monkeypatch(defaultcls)
       
    46     def select_best(self, vobjects, *args, **kwargs):
       
    47         """return an instance of the most specific object according
       
    48         to parameters
       
    49 
       
    50         raise NoSelectableObject if no object apply
       
    51         """
       
    52         for vobjectcls in vobjects:
       
    53             _fix_cls_attrs(self, vobjectcls)
       
    54         selected = orig_select_best(self, vobjects, *args, **kwargs)
       
    55         # redo the same thing on the instance so it won't use equivalent class
       
    56         # attributes (which may change)
       
    57         _fix_cls_attrs(self, selected)
       
    58         return selected
       
    59 
       
    60     etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
       
    61     orig_etype_class = etypescls.orig_etype_class = etypescls.etype_class
       
    62     @monkeypatch(defaultcls)
       
    63     def etype_class(self, etype):
       
    64         """return an entity class for the given entity type.
       
    65         Try to find out a specific class for this kind of entity or
       
    66         default to a dump of the class registered for 'Any'
       
    67         """
       
    68         usercls = orig_etype_class(self, etype)
       
    69         if etype == 'Any':
       
    70             return usercls
       
    71         usercls.e_schema = self.schema.eschema(etype)
       
    72         return usercls
       
    73 
       
    74 def multiple_connections_unfix():
       
    75     defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
       
    76     defaultcls.select_best = defaultcls.orig_select_best
       
    77     etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
       
    78     etypescls.etype_class = etypescls.orig_etype_class
    30 
    79 
    31 class ConnectionProperties(object):
    80 class ConnectionProperties(object):
    32     def __init__(self, cnxtype=None, lang=None, close=True, log=False):
    81     def __init__(self, cnxtype=None, lang=None, close=True, log=False):
    33         self.cnxtype = cnxtype or 'pyro'
    82         self.cnxtype = cnxtype or 'pyro'
    34         self.lang = lang
    83         self.lang = lang
    86             group=None, cnxprops=None, port=None, setvreg=True, mulcnx=True,
   135             group=None, cnxprops=None, port=None, setvreg=True, mulcnx=True,
    87             initlog=True):
   136             initlog=True):
    88     """Constructor for creating a connection to the CubicWeb repository.
   137     """Constructor for creating a connection to the CubicWeb repository.
    89     Returns a Connection object.
   138     Returns a Connection object.
    90 
   139 
    91     When method is 'pyro' and setvreg is True, use a special registry class
   140     When method is 'pyro', setvreg is True, try to deal with connections to
    92     (MulCnxCubicWebRegistry) made to deal with connections to differents instances
   141     differents instances in the same process unless specified otherwise by
    93     in the same process unless specified otherwise by setting the mulcnx to
   142     setting the mulcnx to False.
    94     False.
       
    95     """
   143     """
    96     config = CubicWebNoAppConfiguration()
   144     config = cwconfig.CubicWebNoAppConfiguration()
    97     if host:
   145     if host:
    98         config.global_set_option('pyro-ns-host', host)
   146         config.global_set_option('pyro-ns-host', host)
    99     if port:
   147     if port:
   100         config.global_set_option('pyro-ns-port', port)
   148         config.global_set_option('pyro-ns-port', port)
   101     if group:
   149     if group:
   105     repo = get_repository(method, database, config=config)
   153     repo = get_repository(method, database, config=config)
   106     if method == 'inmemory':
   154     if method == 'inmemory':
   107         vreg = repo.vreg
   155         vreg = repo.vreg
   108     elif setvreg:
   156     elif setvreg:
   109         if mulcnx:
   157         if mulcnx:
   110             vreg = MulCnxCubicWebRegistry(config, initlog=initlog)
   158             multiple_connections_fix()
   111         else:
   159         vreg = cwvreg.CubicWebVRegistry(config, initlog=initlog)
   112             vreg = CubicWebRegistry(config, initlog=initlog)
       
   113         schema = repo.get_schema()
   160         schema = repo.get_schema()
   114         for oldetype, newetype in ETYPE_NAME_MAP.items():
   161         for oldetype, newetype in ETYPE_NAME_MAP.items():
   115             if oldetype in schema:
   162             if oldetype in schema:
   116                 print 'aliasing', newetype, 'to', oldetype
   163                 print 'aliasing', newetype, 'to', oldetype
   117                 schema._entities[newetype] = schema._entities[oldetype]
   164                 schema._entities[newetype] = schema._entities[oldetype]
   124 
   171 
   125 def in_memory_cnx(config, login, password):
   172 def in_memory_cnx(config, login, password):
   126     """usefull method for testing and scripting to get a dbapi.Connection
   173     """usefull method for testing and scripting to get a dbapi.Connection
   127     object connected to an in-memory repository instance
   174     object connected to an in-memory repository instance
   128     """
   175     """
   129     if isinstance(config, CubicWebRegistry):
   176     if isinstance(config, cwvreg.CubicWebVRegistry):
   130         vreg = config
   177         vreg = config
   131         config = None
   178         config = None
   132     else:
   179     else:
   133         vreg = None
   180         vreg = None
   134     # get local access to the repository
   181     # get local access to the repository
   474         eid, login, groups, properties = self._repo.user_info(self.sessionid,
   521         eid, login, groups, properties = self._repo.user_info(self.sessionid,
   475                                                               props)
   522                                                               props)
   476         if req is None:
   523         if req is None:
   477             req = self.request()
   524             req = self.request()
   478         rset = req.eid_rset(eid, 'CWUser')
   525         rset = req.eid_rset(eid, 'CWUser')
   479         user = self.vreg.etype_class('CWUser')(req, rset, row=0, groups=groups,
   526         user = self.vreg['etypes'].etype_class('CWUser')(req, rset, row=0,
   480                                                properties=properties)
   527                                                          groups=groups,
       
   528                                                          properties=properties)
   481         user['login'] = login # cache login
   529         user['login'] = login # cache login
   482         return user
   530         return user
   483 
   531 
   484     def __del__(self):
   532     def __del__(self):
   485         """close the remote connection if necessary"""
   533         """close the remote connection if necessary"""