dbapi.py
changeset 2675 f84ba1a66abb
parent 2665 0c6281487f90
child 2770 356e9d7c356d
child 3110 757d36162235
--- a/dbapi.py	Tue Aug 04 15:06:09 2009 +0200
+++ b/dbapi.py	Tue Aug 04 15:08:18 2009 +0200
@@ -16,9 +16,11 @@
 from itertools import count
 
 from logilab.common.logging_ext import set_log_methods
+from logilab.common.decorators import monkeypatch
+from logilab.common.deprecation import deprecated
+
 from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn
-from cubicweb.cwvreg import CubicWebRegistry, MulCnxCubicWebRegistry
-from cubicweb.cwconfig import CubicWebNoAppConfiguration
+from cubicweb import cwvreg, cwconfig
 
 _MARKER = object()
 
@@ -28,6 +30,54 @@
     except KeyError:
         return ''
 
+def _fix_cls_attrs(reg, appobject):
+    appobject.vreg = reg.vreg
+    appobject.schema = reg.schema
+    appobject.config = reg.config
+
+def multiple_connections_fix():
+    """some monkey patching necessary when an application has to deal with
+    several connections to different repositories. It tries to hide buggy class
+    attributes since classes are not designed to be shared among multiple
+    registries.
+    """
+    defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
+    orig_select_best = defaultcls.orig_select_best = defaultcls.select_best
+    @monkeypatch(defaultcls)
+    def select_best(self, appobjects, *args, **kwargs):
+        """return an instance of the most specific object according
+        to parameters
+
+        raise NoSelectableObject if no object apply
+        """
+        for appobjectcls in appobjects:
+            _fix_cls_attrs(self, appobjectcls)
+        selected = orig_select_best(self, appobjects, *args, **kwargs)
+        # redo the same thing on the instance so it won't use equivalent class
+        # attributes (which may change)
+        _fix_cls_attrs(self, selected)
+        return selected
+
+    etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
+    orig_etype_class = etypescls.orig_etype_class = etypescls.etype_class
+    @monkeypatch(defaultcls)
+    def etype_class(self, etype):
+        """return an entity class for the given entity type.
+        Try to find out a specific class for this kind of entity or
+        default to a dump of the class registered for 'Any'
+        """
+        usercls = orig_etype_class(self, etype)
+        if etype == 'Any':
+            return usercls
+        usercls.e_schema = self.schema.eschema(etype)
+        return usercls
+
+def multiple_connections_unfix():
+    defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None]
+    defaultcls.select_best = defaultcls.orig_select_best
+    etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes']
+    etypescls.etype_class = etypescls.orig_etype_class
+
 class ConnectionProperties(object):
     def __init__(self, cnxtype=None, lang=None, close=True, log=False):
         self.cnxtype = cnxtype or 'pyro'
@@ -51,24 +101,14 @@
         from cubicweb.server.repository import Repository
         return Repository(config, vreg=vreg)
     else: # method == 'pyro'
-        from Pyro import core, naming
-        from Pyro.errors import NamingError, ProtocolError
-        core.initClient(banner=0)
-        nsid = ':%s.%s' % (config['pyro-ns-group'], database)
-        locator = naming.NameServerLocator()
         # resolve the Pyro object
+        from logilab.common.pyro_ext import ns_get_proxy
         try:
-            nshost, nsport = config['pyro-ns-host'], config['pyro-ns-port']
-            uri = locator.getNS(nshost, nsport).resolve(nsid)
-        except ProtocolError:
-            raise ConnectionError('Could not connect to the Pyro name server '
-                                  '(host: %s:%i)' % (nshost, nsport))
-        except NamingError:
-            raise ConnectionError('Could not get repository for %s '
-                                  '(not registered in Pyro), '
-                                  'you may have to restart your server-side '
-                                  'instance' % nsid)
-        return core.getProxyForURI(uri)
+            return ns_get_proxy(database,
+                                defaultnsgroup=config['pyro-ns-group'],
+                                nshost=config['pyro-ns-host'])
+        except Exception, ex:
+            raise ConnectionError(str(ex))
 
 def repo_connect(repo, login, password, cnxprops=None):
     """Constructor to create a new connection to the CubicWeb repository.
@@ -82,22 +122,18 @@
         cnx.vreg = repo.vreg
     return cnx
 
-def connect(database=None, login=None, password=None, host=None,
-            group=None, cnxprops=None, port=None, setvreg=True, mulcnx=True,
-            initlog=True):
+def connect(database=None, login=None, password=None, host=None, group=None,
+            cnxprops=None, setvreg=True, mulcnx=True, initlog=True):
     """Constructor for creating a connection to the CubicWeb repository.
     Returns a Connection object.
 
-    When method is 'pyro' and setvreg is True, use a special registry class
-    (MulCnxCubicWebRegistry) made to deal with connections to differents instances
-    in the same process unless specified otherwise by setting the mulcnx to
-    False.
+    When method is 'pyro', setvreg is True, try to deal with connections to
+    differents instances in the same process unless specified otherwise by
+    setting the mulcnx to False.
     """
-    config = CubicWebNoAppConfiguration()
+    config = cwconfig.CubicWebNoAppConfiguration()
     if host:
         config.global_set_option('pyro-ns-host', host)
-    if port:
-        config.global_set_option('pyro-ns-port', port)
     if group:
         config.global_set_option('pyro-ns-group', group)
     cnxprops = cnxprops or ConnectionProperties()
@@ -107,9 +143,8 @@
         vreg = repo.vreg
     elif setvreg:
         if mulcnx:
-            vreg = MulCnxCubicWebRegistry(config, initlog=initlog)
-        else:
-            vreg = CubicWebRegistry(config, initlog=initlog)
+            multiple_connections_fix()
+        vreg = cwvreg.CubicWebVRegistry(config, initlog=initlog)
         schema = repo.get_schema()
         for oldetype, newetype in ETYPE_NAME_MAP.items():
             if oldetype in schema:
@@ -126,7 +161,7 @@
     """usefull method for testing and scripting to get a dbapi.Connection
     object connected to an in-memory repository instance
     """
-    if isinstance(config, CubicWebRegistry):
+    if isinstance(config, cwvreg.CubicWebVRegistry):
         vreg = config
         config = None
     else:
@@ -401,7 +436,7 @@
             raise ProgrammingError('Closed connection')
         return self._repo.get_schema()
 
-    def load_vobjects(self, cubes=_MARKER, subpath=None, expand=True,
+    def load_appobjects(self, cubes=_MARKER, subpath=None, expand=True,
                       force_reload=None):
         config = self.vreg.config
         if cubes is _MARKER:
@@ -434,11 +469,13 @@
             if self._repo.config.instance_hooks:
                 hm.register_hooks(config.load_hooks(self.vreg))
 
+    load_vobjects = deprecated()(load_appobjects)
+
     def use_web_compatible_requests(self, baseurl, sitetitle=None):
         """monkey patch DBAPIRequest to fake a cw.web.request, so you should
         able to call html views using rset from a simple dbapi connection.
 
-        You should call `load_vobjects` at some point to register those views.
+        You should call `load_appobjects` at some point to register those views.
         """
         from cubicweb.web.request import CubicWebRequestBase as cwrb
         DBAPIRequest.build_ajax_replace_url = cwrb.build_ajax_replace_url.im_func
@@ -476,8 +513,9 @@
         if req is None:
             req = self.request()
         rset = req.eid_rset(eid, 'CWUser')
-        user = self.vreg.etype_class('CWUser')(req, rset, row=0, groups=groups,
-                                               properties=properties)
+        user = self.vreg['etypes'].etype_class('CWUser')(req, rset, row=0,
+                                                         groups=groups,
+                                                         properties=properties)
         user['login'] = login # cache login
         return user