dbapi.py
brancholdstable
changeset 4985 02b52bf9f5f8
parent 4721 8f63691ccb7f
child 4768 430b89aed996
equal deleted inserted replaced
4563:c25da7573ebd 4985:02b52bf9f5f8
    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
    19 from logilab.common.decorators import monkeypatch
    20 from logilab.common.deprecation import deprecated
    20 from logilab.common.deprecation import deprecated
    21 
    21 
    22 from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn
    22 from cubicweb import ETYPE_NAME_MAP, ConnectionError, cwvreg, cwconfig
    23 from cubicweb import cwvreg, cwconfig
    23 from cubicweb.req import RequestSessionBase
       
    24 
    24 
    25 
    25 _MARKER = object()
    26 _MARKER = object()
    26 
    27 
    27 def _fake_property_value(self, name):
    28 def _fake_property_value(self, name):
    28     try:
    29     try:
    29         return super(dbapi.DBAPIRequest, self).property_value(name)
    30         return super(DBAPIRequest, self).property_value(name)
    30     except KeyError:
    31     except KeyError:
    31         return ''
    32         return ''
    32 
       
    33 def _fix_cls_attrs(reg, appobject):
       
    34     appobject.vreg = reg.vreg
       
    35     appobject.schema = reg.schema
       
    36     appobject.config = reg.config
       
    37 
    33 
    38 def multiple_connections_fix():
    34 def multiple_connections_fix():
    39     """some monkey patching necessary when an application has to deal with
    35     """some monkey patching necessary when an application has to deal with
    40     several connections to different repositories. It tries to hide buggy class
    36     several connections to different repositories. It tries to hide buggy class
    41     attributes since classes are not designed to be shared among multiple
    37     attributes since classes are not designed to be shared among multiple
    42     registries.
    38     registries.
    43     """
    39     """
    44     defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
    40     defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
    45     orig_select_best = defaultcls.orig_select_best = defaultcls.select_best
       
    46     @monkeypatch(defaultcls)
       
    47     def select_best(self, appobjects, *args, **kwargs):
       
    48         """return an instance of the most specific object according
       
    49         to parameters
       
    50 
       
    51         raise NoSelectableObject if no object apply
       
    52         """
       
    53         for appobjectcls in appobjects:
       
    54             _fix_cls_attrs(self, appobjectcls)
       
    55         selected = orig_select_best(self, appobjects, *args, **kwargs)
       
    56         # redo the same thing on the instance so it won't use equivalent class
       
    57         # attributes (which may change)
       
    58         _fix_cls_attrs(self, selected)
       
    59         return selected
       
    60 
    41 
    61     etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
    42     etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
    62     orig_etype_class = etypescls.orig_etype_class = etypescls.etype_class
    43     orig_etype_class = etypescls.orig_etype_class = etypescls.etype_class
    63     @monkeypatch(defaultcls)
    44     @monkeypatch(defaultcls)
    64     def etype_class(self, etype):
    45     def etype_class(self, etype):
    71             return usercls
    52             return usercls
    72         usercls.e_schema = self.schema.eschema(etype)
    53         usercls.e_schema = self.schema.eschema(etype)
    73         return usercls
    54         return usercls
    74 
    55 
    75 def multiple_connections_unfix():
    56 def multiple_connections_unfix():
    76     defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
       
    77     defaultcls.select_best = defaultcls.orig_select_best
       
    78     etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
    57     etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
    79     etypescls.etype_class = etypescls.orig_etype_class
    58     etypescls.etype_class = etypescls.orig_etype_class
    80 
    59 
    81 class ConnectionProperties(object):
    60 class ConnectionProperties(object):
    82     def __init__(self, cnxtype=None, lang=None, close=True, log=False):
    61     def __init__(self, cnxtype=None, lang=None, close=True, log=False):
   108                                 defaultnsgroup=config['pyro-ns-group'],
    87                                 defaultnsgroup=config['pyro-ns-group'],
   109                                 nshost=config['pyro-ns-host'])
    88                                 nshost=config['pyro-ns-host'])
   110         except Exception, ex:
    89         except Exception, ex:
   111             raise ConnectionError(str(ex))
    90             raise ConnectionError(str(ex))
   112 
    91 
   113 def repo_connect(repo, login, password, cnxprops=None):
    92 def repo_connect(repo, login, **kwargs):
   114     """Constructor to create a new connection to the CubicWeb repository.
    93     """Constructor to create a new connection to the CubicWeb repository.
   115 
    94 
   116     Returns a Connection instance.
    95     Returns a Connection instance.
   117     """
    96     """
   118     cnxprops = cnxprops or ConnectionProperties('inmemory')
    97     if not 'cnxprops' in kwargs:
   119     cnxid = repo.connect(unicode(login), password, cnxprops=cnxprops)
    98         kwargs['cnxprops'] = ConnectionProperties('inmemory')
   120     cnx = Connection(repo, cnxid, cnxprops)
    99     cnxid = repo.connect(unicode(login), **kwargs)
   121     if cnxprops.cnxtype == 'inmemory':
   100     cnx = Connection(repo, cnxid, kwargs['cnxprops'])
       
   101     if kwargs['cnxprops'].cnxtype == 'inmemory':
   122         cnx.vreg = repo.vreg
   102         cnx.vreg = repo.vreg
   123     return cnx
   103     return cnx
   124 
   104 
   125 def connect(database=None, login=None, password=None, host=None, group=None,
   105 def connect(database=None, login=None, host=None, group=None,
   126             cnxprops=None, setvreg=True, mulcnx=True, initlog=True):
   106             cnxprops=None, setvreg=True, mulcnx=True, initlog=True, **kwargs):
   127     """Constructor for creating a connection to the CubicWeb repository.
   107     """Constructor for creating a connection to the CubicWeb repository.
   128     Returns a Connection object.
   108     Returns a Connection object.
   129 
   109 
   130     When method is 'pyro', setvreg is True, try to deal with connections to
   110     When method is 'pyro', setvreg is True, try to deal with connections to
   131     differents instances in the same process unless specified otherwise by
   111     differents instances in the same process unless specified otherwise by
   151                 print 'aliasing', newetype, 'to', oldetype
   131                 print 'aliasing', newetype, 'to', oldetype
   152                 schema._entities[newetype] = schema._entities[oldetype]
   132                 schema._entities[newetype] = schema._entities[oldetype]
   153         vreg.set_schema(schema)
   133         vreg.set_schema(schema)
   154     else:
   134     else:
   155         vreg = None
   135         vreg = None
   156     cnx = repo_connect(repo, login, password, cnxprops)
   136     cnx = repo_connect(repo, login, cnxprops=cnxprops, **kwargs)
   157     cnx.vreg = vreg
   137     cnx.vreg = vreg
   158     return cnx
   138     return cnx
   159 
   139 
   160 def in_memory_cnx(config, login, password):
   140 def in_memory_cnx(config, login, **kwargs):
   161     """usefull method for testing and scripting to get a dbapi.Connection
   141     """usefull method for testing and scripting to get a dbapi.Connection
   162     object connected to an in-memory repository instance
   142     object connected to an in-memory repository instance
   163     """
   143     """
   164     if isinstance(config, cwvreg.CubicWebVRegistry):
   144     if isinstance(config, cwvreg.CubicWebVRegistry):
   165         vreg = config
   145         vreg = config
   168         vreg = None
   148         vreg = None
   169     # get local access to the repository
   149     # get local access to the repository
   170     repo = get_repository('inmemory', config=config, vreg=vreg)
   150     repo = get_repository('inmemory', config=config, vreg=vreg)
   171     # connection to the CubicWeb repository
   151     # connection to the CubicWeb repository
   172     cnxprops = ConnectionProperties('inmemory')
   152     cnxprops = ConnectionProperties('inmemory')
   173     cnx = repo_connect(repo, login, password, cnxprops=cnxprops)
   153     cnx = repo_connect(repo, login, cnxprops=cnxprops, **kwargs)
   174     return repo, cnx
   154     return repo, cnx
   175 
   155 
   176 
   156 
   177 class DBAPIRequest(RequestSessionMixIn):
   157 class DBAPIRequest(RequestSessionBase):
   178 
   158 
   179     def __init__(self, vreg, cnx=None):
   159     def __init__(self, vreg, cnx=None):
   180         super(DBAPIRequest, self).__init__(vreg)
   160         super(DBAPIRequest, self).__init__(vreg)
   181         try:
   161         try:
   182             # no vreg or config which doesn't handle translations
   162             # no vreg or config which doesn't handle translations
   218             self._ = self.__ = gettext
   198             self._ = self.__ = gettext
   219             self.pgettext = pgettext
   199             self.pgettext = pgettext
   220         except KeyError:
   200         except KeyError:
   221             # this occurs usually during test execution
   201             # this occurs usually during test execution
   222             self._ = self.__ = unicode
   202             self._ = self.__ = unicode
   223             self.pgettext = lambda x,y: y
   203             self.pgettext = lambda x, y: y
   224         self.debug('request default language: %s', self.lang)
   204         self.debug('request default language: %s', self.lang)
   225 
   205 
   226     def decorate_rset(self, rset):
   206     def decorate_rset(self, rset):
   227         rset.vreg = self.vreg
   207         rset.vreg = self.vreg
   228         rset.req = self
   208         rset.req = self
   259         """return a dictionnary containing session data"""
   239         """return a dictionnary containing session data"""
   260         return self.cnx.session_data()
   240         return self.cnx.session_data()
   261 
   241 
   262     def get_session_data(self, key, default=None, pop=False):
   242     def get_session_data(self, key, default=None, pop=False):
   263         """return value associated to `key` in session data"""
   243         """return value associated to `key` in session data"""
       
   244         if self.cnx is None:
       
   245             return None # before the connection has been established
   264         return self.cnx.get_session_data(key, default, pop)
   246         return self.cnx.get_session_data(key, default, pop)
   265 
   247 
   266     def set_session_data(self, key, value):
   248     def set_session_data(self, key, value):
   267         """set value associated to `key` in session data"""
   249         """set value associated to `key` in session data"""
   268         return self.cnx.set_session_data(key, value)
   250         return self.cnx.set_session_data(key, value)