[db-api/configuration] simplify db-api and configuration so that all the connection information is in the repository url, closes #2521848
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 21 Jan 2013 18:01:25 +0100
changeset 8669 62213a34726e
parent 8668 4fea61c636b2
child 8670 f02139297beb
[db-api/configuration] simplify db-api and configuration so that all the connection information is in the repository url, closes #2521848 eg no more specific option of pyro ns host, group, etc. This also fixes broken ZMQ sources. Changes: * dropped pyro-ns-host, pyro-instance-id, pyro-ns-group from client side config, in favor of repository-uri. No migration done, supposing there is **no web-only config** in the wild. Also stop discovering the connection method through the repo_method class attribute of the configuration, varying according to the configuration class. This is a first step on the way to a simpler configuration handling. Notice those pyro options are still available for repository only / all-in-one configurations as they are needed to configure the pyro server. * stop telling connection method using ConnectionProperties, this is so boring. Also, drop _cnxtype from Connection and cnxtype from Session. The former is replaced by a is_repo_in_memory property and the later is totaly useless. * deprecate in_memory_cnx which becomes useless, use _repo_connect instead
cwconfig.py
cwctl.py
dbapi.py
devtools/__init__.py
doc/3.16.rst
etwist/server.py
etwist/twconfig.py
server/migractions.py
server/serverconfig.py
server/serverctl.py
server/session.py
server/test/unittest_repository.py
web/views/authentication.py
web/views/debug.py
web/webconfig.py
web/webctl.py
--- a/cwconfig.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/cwconfig.py	Mon Jan 21 18:01:25 2013 +0100
@@ -353,28 +353,6 @@
           'help': 'permission umask for files created by the server',
           'group': 'main', 'level': 2,
           }),
-        # pyro options
-        ('pyro-instance-id',
-         {'type' : 'string',
-          'default': Method('default_instance_id'),
-          'help': 'identifier of the CubicWeb instance in the Pyro name server',
-          'group': 'pyro', 'level': 1,
-          }),
-        ('pyro-ns-host',
-         {'type' : 'string',
-          'default': '',
-          'help': 'Pyro name server\'s host. If not set, will be detected by a \
-broadcast query. It may contains port information using <host>:<port> notation. \
-Use "NO_PYRONS" to create a Pyro server but not register to a pyro nameserver',
-          'group': 'pyro', 'level': 1,
-          }),
-        ('pyro-ns-group',
-         {'type' : 'string',
-          'default': 'cubicweb',
-          'help': 'Pyro name server\'s group where the repository will be \
-registered.',
-          'group': 'pyro', 'level': 1,
-          }),
         # common configuration options which are potentially required as soon as
         # you're using "base" application objects (ie to really server/web
         # specific)
--- a/cwctl.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/cwctl.py	Mon Jan 21 18:01:25 2013 +0100
@@ -27,6 +27,7 @@
 import sys
 from warnings import warn
 from os import remove, listdir, system, pathsep
+from os.path import exists, join, isfile, isdir, dirname, abspath
 try:
     from os import kill, getpgid
 except ImportError:
@@ -36,9 +37,6 @@
         """win32 getpgid implementation"""
 
 
-from os.path import exists, join, isfile, isdir, dirname, abspath
-
-from urlparse import urlparse
 
 from logilab.common.clcommands import CommandLine
 from logilab.common.shellutils import ASK
@@ -874,40 +872,30 @@
           'help': 'URI of the CubicWeb repository to connect to. URI can be \
 pyro://[host:port] the Pyro name server host; if the pyro nameserver is not set, \
 it will be detected by using a broadcast query, a ZMQ URL or \
-inmemory:// (default) use an in-memory repository.',
+inmemory:// (default) use an in-memory repository. THIS OPTION IS DEPRECATED, \
+directly give URI as instance id instead',
           'group': 'remote'
           }),
         )
 
     def run(self, args):
-        appid = args.pop(0)
+        from urlparse import urlparse
+        appuri = args.pop(0)
         if self.config.repo_uri:
-            uri = urlparse(self.config.repo_uri)
-            if uri.scheme == 'pyro':
-                cnxtype = uri.scheme
-                hostport = uri.netloc
-            elif uri.scheme == 'inmemory':
-                cnxtype = ''
-                hostport = ''
-            else:
-                cnxtype = 'zmq'
-                hostport = self.config.repo_uri
-        else:
-            cnxtype = ''
-
-        if cnxtype:
+            warn('[3.16] --repo-uri option is deprecated, directly give the URI as instance id',
+                 DeprecationWarning)
+            if urlparse(self.config.repo_uri).scheme in ('pyro', 'inmemory'):
+                appuri = '%s/%s' % (self.config.repo_uri.rstrip('/'), appuri)
+        scheme = urlparse(self.config.repo_uri).scheme
+        if scheme not in ('', 'inmemory'):
             from cubicweb import AuthenticationError
-            from cubicweb.dbapi import connect, ConnectionProperties
+            from cubicweb.dbapi import connect
             from cubicweb.server.utils import manager_userpasswd
             from cubicweb.server.migractions import ServerMigrationHelper
-            cnxprops = ConnectionProperties(cnxtype=cnxtype)
-
             while True:
                 try:
                     login, pwd = manager_userpasswd(msg=None)
-                    cnx = connect(appid, login=login, password=pwd,
-                                  host=hostport, mulcnx=False,
-                                  cnxprops=cnxprops)
+                    cnx = connect(appuri, login=login, password=pwd, mulcnx=False)
                 except AuthenticationError, ex:
                     print ex
                 except (KeyboardInterrupt, EOFError):
@@ -943,7 +931,7 @@
             else:
                 mih.interactive_shell()
         finally:
-            if not cnxtype: # shutdown in-memory repo
+            if scheme in ('', 'inmemory'): # shutdown in-memory repo
                 mih.shutdown()
             else:
                 cnx.close()
--- a/dbapi.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/dbapi.py	Mon Jan 21 18:01:25 2013 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -31,6 +31,7 @@
 from warnings import warn
 from os.path import join
 from uuid import uuid4
+from urlparse import  urlparse
 
 from logilab.common.logging_ext import set_log_methods
 from logilab.common.decorators import monkeypatch
@@ -81,56 +82,70 @@
 
 class ConnectionProperties(object):
     def __init__(self, cnxtype=None, close=True, log=False):
-        self.cnxtype = cnxtype or 'pyro'
+        if cnxtype is not None:
+            warn('[3.16] cnxtype argument is deprecated', DeprecationWarning,
+                 stacklevel=2)
+        self.cnxtype = cnxtype
         self.log_queries = log
         self.close_on_del = close
 
 
-def get_repository(method, database=None, config=None, vreg=None):
-    """get a proxy object to the CubicWeb repository, using a specific RPC method.
+def get_repository(uri=None, config=None, vreg=None):
+    """get a repository for the given URI or config/vregistry (in case we're
+    loading the repository for a client, eg web server, configuration).
 
-    Only 'in-memory' and 'pyro' are supported for now. Either vreg or config
-    argument should be given
+    The returned repository may be an in-memory repository or a proxy object
+    using a specific RPC method, depending on the given URI (pyro or zmq).
     """
-    assert method in ('pyro', 'inmemory', 'zmq')
-    assert vreg or config
-    if vreg and not config:
-        config = vreg.config
+    if uri is None:
+        uri = config['repository-uri'] or config.appid
+    puri = urlparse(uri)
+    method = puri.scheme.lower() or 'inmemory'
     if method == 'inmemory':
         # get local access to the repository
         from cubicweb.server.repository import Repository
         from cubicweb.server.utils import TasksManager
         return Repository(config, TasksManager(), vreg=vreg)
-    elif method == 'zmq':
-        from cubicweb.zmqclient import ZMQRepositoryClient
-        return ZMQRepositoryClient(database)
-    else: # method == 'pyro'
+    elif method in ('pyro', 'pyroloc'):
         # resolve the Pyro object
         from logilab.common.pyro_ext import ns_get_proxy, get_proxy
-        pyroid = database or config['pyro-instance-id'] or config.appid
         try:
-            if config['pyro-ns-host'] == 'NO_PYRONS':
-                return get_proxy(pyroid)
+            if puri.scheme == 'pyroloc':
+                return get_proxy(uri)
+            path = puri.path.rstrip('/')
+            if not path:
+                raise ConnectionError(
+                    "can't find instance name in %s (expected to be the path component)"
+                    % uri)
+            if '.' in path:
+                nsgroup, nsid = path.rsplit('.', 1)
             else:
-                return ns_get_proxy(pyroid, defaultnsgroup=config['pyro-ns-group'],
-                                    nshost=config['pyro-ns-host'])
+                nsgroup = 'cubicweb'
+                nsid = path
+            return ns_get_proxy(nsid, defaultnsgroup=nsgroup, nshost=puri.netloc)
         except Exception, ex:
             raise ConnectionError(str(ex))
+    elif method == 'tcp': # use zmq (see zmq documentation)
+        from cubicweb.zmqclient import ZMQRepositoryClient
+        return ZMQRepositoryClient(uri)
+    else:
+        raise ConnectionError('unknown protocol: `%s`' % method)
+
 
 def repo_connect(repo, login, **kwargs):
-    """Constructor to create a new connection to the CubicWeb repository.
+    """Constructor to create a new connection to the given CubicWeb repository.
 
     Returns a Connection instance.
+
+    Raises AuthenticationError if authentication failed
     """
-    if not 'cnxprops' in kwargs:
-        kwargs['cnxprops'] = ConnectionProperties('inmemory')
     cnxid = repo.connect(unicode(login), **kwargs)
-    cnx = Connection(repo, cnxid, kwargs['cnxprops'])
-    if kwargs['cnxprops'].cnxtype == 'inmemory':
+    cnx = Connection(repo, cnxid, kwargs.get('cnxprops'))
+    if cnx.is_repo_in_memory:
         cnx.vreg = repo.vreg
     return cnx
 
-def connect(database=None, login=None, host=None, group=None,
+def connect(database, login=None,
             cnxprops=None, setvreg=True, mulcnx=True, initlog=True, **kwargs):
     """Constructor for creating a connection to the CubicWeb repository.
     Returns a :class:`Connection` object.
@@ -139,24 +154,31 @@
 
       cnx = connect('myinstance', login='me', password='toto')
 
-    Arguments:
+    `database` may be:
+
+    * a simple instance id for in-memory connection
+
+    * an uri like scheme://host:port/instanceid where scheme may be one of
+      'pyro', 'pyroloc', 'inmemory' or a schema supported by ZMQ
 
-    :database:
-      the instance's pyro identifier.
+      * if scheme is 'pyro', <host:port> determine the name server address. If
+        not specified (e.g. 'pyro:///instanceid'), it will be detected through a
+        broadcast query. The instance id is the name of the instance in the name
+        server and may be prefixed by a group (e.g.
+        'pyro:///:cubicweb.instanceid')
+
+      * if scheme is 'pyroloc', it's expected to be a bare pyro location URI
+
+      * if scheme is handled by ZMQ (eg 'tcp'), you should not specify an
+        instance id
+
+    Other arguments:
 
     :login:
       the user login to use to authenticate.
 
-    :host:
-      - pyro: nameserver host. Will be detected using broadcast query if unspecified
-      - zmq: repository host socket address
-
-    :group:
-      the instance's pyro nameserver group. You don't have to specify it unless
-      tweaked in instance's configuration.
-
     :cnxprops:
-      an optional :class:`ConnectionProperties` instance, allowing to specify
+      a :class:`ConnectionProperties` instance, allowing to specify
       the connection method (eg in memory or pyro). A Pyro connection will be
       established if you don't specify that argument.
 
@@ -178,20 +200,25 @@
       there goes authentication tokens. You usually have to specify a password
       for the given user, using a named 'password' argument.
     """
-    cnxprops = cnxprops or ConnectionProperties()
-    method = cnxprops.cnxtype
-    if method == 'pyro':
+    if urlparse(database).scheme is None:
+        warn('[3.16] give an qualified URI as database instead of using '
+             'host/cnxprops to specify the connection method',
+             DeprecationWarning, stacklevel=2)
+        if cnxprops.cnxtype == 'zmq':
+            database = kwargs.pop('host')
+        elif cnxprops.cnxtype == 'inmemory':
+            database = 'inmemory://' + database
+        else:
+            database = 'pyro://%s/%s.%s' % (kwargs.pop('host', ''),
+                                            kwargs.pop('group', 'cubicweb'),
+                                            database)
+    puri = urlparse(database)
+    method = puri.scheme.lower()
+    if method == 'inmemory':
+        config = cwconfig.instance_configuration(puuri.path)
+    else:
         config = cwconfig.CubicWebNoAppConfiguration()
-        if host:
-            config.global_set_option('pyro-ns-host', host)
-        if group:
-            config.global_set_option('pyro-ns-group', group)
-    elif method == 'zmq':
-        config = cwconfig.CubicWebNoAppConfiguration()
-    else:
-        assert database
-        config = cwconfig.instance_configuration(database)
-    repo = get_repository(method, database, config=config)
+    repo = get_repository(database, config=config)
     if method == 'inmemory':
         vreg = repo.vreg
     elif setvreg:
@@ -218,14 +245,7 @@
     else:
         vreg = None
     # get local access to the repository
-    return get_repository('inmemory', config=config, vreg=vreg)
-
-def in_memory_cnx(repo, login, **kwargs):
-    """Establish a In memory connection to a <repo> for the user with <login>
-
-    additionel credential might be required"""
-    cnxprops = ConnectionProperties('inmemory')
-    return repo_connect(repo, login, cnxprops=cnxprops, **kwargs)
+    return get_repository('inmemory://', config=config, vreg=vreg)
 
 def in_memory_repo_cnx(config, login, **kwargs):
     """useful method for testing and scripting to get a dbapi.Connection
@@ -233,9 +253,9 @@
     """
     # connection to the CubicWeb repository
     repo = in_memory_repo(config)
-    return repo, in_memory_cnx(repo, login, **kwargs)
+    return repo, repo_connect(repo, login, **kwargs)
 
-
+# XXX web only method, move to webconfig?
 def anonymous_session(vreg):
     """return a new anonymous session
 
@@ -245,11 +265,9 @@
     if anoninfo is None: # no anonymous user
         raise AuthenticationError('anonymous access is not authorized')
     anon_login, anon_password = anoninfo
-    cnxprops = ConnectionProperties(vreg.config.repo_method)
     # use vreg's repository cache
     repo = vreg.config.repository(vreg)
-    anon_cnx = repo_connect(repo, anon_login,
-                            cnxprops=cnxprops, password=anon_password)
+    anon_cnx = repo_connect(repo, anon_login, password=anon_password)
     anon_cnx.vreg = vreg
     return DBAPISession(anon_cnx, anon_login)
 
@@ -281,6 +299,7 @@
     def __repr__(self):
         return '<DBAPISession %r>' % self.sessionid
 
+
 class DBAPIRequest(RequestSessionBase):
     #: Request language identifier eg: 'en'
     lang = None
@@ -535,15 +554,22 @@
         self._repo = repo
         self.sessionid = cnxid
         self._close_on_del = getattr(cnxprops, 'close_on_del', True)
-        self._cnxtype = getattr(cnxprops, 'cnxtype', 'pyro')
         self._web_request = False
         if cnxprops and cnxprops.log_queries:
             self.executed_queries = []
             self.cursor_class = LogCursor
-        if self._cnxtype == 'pyro':
-            # check client/server compat
-            if self._repo.get_versions()['cubicweb'] < (3, 8, 6):
-                self._txid = lambda cursor=None: {}
+
+    @property
+    def is_repo_in_memory(self):
+        """return True if this is a local, aka in-memory, connection to the
+        repository
+        """
+        try:
+            from cubicweb.server.repository import Repository
+        except ImportError:
+            # code not available, no way
+            return False
+        return isinstance(self._repo, Repository)
 
     def __repr__(self):
         if self.anonymous_connection:
@@ -850,3 +876,5 @@
         """
         return self._repo.undo_transaction(self.sessionid, txuuid,
                                            **self._txid())
+
+in_memory_cnx = deprecated('[3.16] use repo_connect instead)')(repo_connect)
--- a/devtools/__init__.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/devtools/__init__.py	Mon Jan 21 18:01:25 2013 +0100
@@ -217,7 +217,6 @@
 
 
 class BaseApptestConfiguration(TestServerConfiguration, TwistedConfiguration):
-    repo_method = 'inmemory'
     name = 'all-in-one' # so it search for all-in-one.conf, not repository.conf
     options = cwconfig.merge_options(TestServerConfiguration.options
                                      + TwistedConfiguration.options)
@@ -385,15 +384,14 @@
         repo.turn_repo_off = partial(turn_repo_off, repo)
         return repo
 
-
     def get_cnx(self):
         """return Connection object on the current repository"""
-        from cubicweb.dbapi import in_memory_cnx
+        from cubicweb.dbapi import repo_connect
         repo = self.get_repo()
         sources = self.config.sources()
         login  = unicode(sources['admin']['login'])
         password = sources['admin']['password'] or 'xxx'
-        cnx = in_memory_cnx(repo, login, password=password)
+        cnx = repo_connect(repo, login, password=password)
         return cnx
 
     def get_repo_and_cnx(self, db_id=DEFAULT_EMPTY_DB_ID):
--- a/doc/3.16.rst	Thu Jan 10 23:05:45 2013 +0100
+++ b/doc/3.16.rst	Mon Jan 21 18:01:25 2013 +0100
@@ -9,9 +9,34 @@
   flushing information in SQL.  This may only be used with PostgreSQL, as it
   requires the 'COPY FROM' command.
 
+
 API changes
 -----------
 
+* db-api/configuration: all the external repository connection information is
+  now in an URL (see #2521848), allowing to drop specific options of pyro ns
+  host, group, etc and fix broken ZMQ source. Configuration related changes:
+
+  * Dropped 'pyro-ns-host', 'pyro-instance-id', 'pyro-ns-group' from client side
+    config, in favor of 'repository-uri'. **NO MIGRATION DONE**, supposing there
+    is no web-only config in the wild.
+
+  * Stop discovering the connection method through `repo_method` class attribute
+    of the configuration, varying according to the configuration class. This is
+    a first step on the way to a simpler configuration handling.
+
+  DB-API related changes:
+
+  * Stop indicating the connection method using `ConnectionProperties`.
+
+  * Drop `_cnxtype` attribute from `Connection` and `cnxtype` from
+    `Session`. The former is replaced by a is_repo_in_memory property
+    and the later is totaly useless.
+
+  * Deprecate `in_memory_cnx` which becomes useless, use `_repo_connect` instead
+    if necessary.
+
+
 Unintrusive API changes
 -----------------------
 
--- a/etwist/server.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/etwist/server.py	Mon Jan 21 18:01:25 2013 +0100
@@ -85,7 +85,7 @@
         config = self.config
         # when we have an in-memory repository, clean unused sessions every XX
         # seconds and properly shutdown the server
-        if config.repo_method == 'inmemory':
+        if config['repository-uri'] == 'inmemory://':
             if config.pyro_enabled():
                 # if pyro is enabled, we have to register to the pyro name
                 # server, create a pyro daemon, and create a task to handle pyro
--- a/etwist/twconfig.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/etwist/twconfig.py	Mon Jan 21 18:01:25 2013 +0100
@@ -115,7 +115,6 @@
     class AllInOneConfiguration(TwistedConfiguration, ServerConfiguration):
         """repository and web instance in the same twisted process"""
         name = 'all-in-one'
-        repo_method = 'inmemory'
         options = merge_options(TwistedConfiguration.options
                                 + ServerConfiguration.options)
 
--- a/server/migractions.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/server/migractions.py	Mon Jan 21 18:01:25 2013 +0100
@@ -132,7 +132,7 @@
 
     @cached
     def repo_connect(self):
-        self.repo = get_repository(method='inmemory', config=self.config)
+        self.repo = get_repository(config=self.config)
         return self.repo
 
     def cube_upgraded(self, cube, version):
--- a/server/serverconfig.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/server/serverconfig.py	Mon Jan 21 18:01:25 2013 +0100
@@ -195,7 +195,7 @@
 notified of every changes.',
           'group': 'email', 'level': 2,
           }),
-        # pyro server.serverconfig
+        # pyro services config
         ('pyro-host',
          {'type' : 'string',
           'default': None,
@@ -204,6 +204,27 @@
 and if not set, it will be choosen randomly',
           'group': 'pyro', 'level': 3,
           }),
+        ('pyro-instance-id',
+         {'type' : 'string',
+          'default': lgconfig.Method('default_instance_id'),
+          'help': 'identifier of the CubicWeb instance in the Pyro name server',
+          'group': 'pyro', 'level': 1,
+          }),
+        ('pyro-ns-host',
+         {'type' : 'string',
+          'default': '',
+          'help': 'Pyro name server\'s host. If not set, will be detected by a \
+broadcast query. It may contains port information using <host>:<port> notation. \
+Use "NO_PYRONS" to create a Pyro server but not register to a pyro nameserver',
+          'group': 'pyro', 'level': 1,
+          }),
+        ('pyro-ns-group',
+         {'type' : 'string',
+          'default': 'cubicweb',
+          'help': 'Pyro name server\'s group where the repository will be \
+registered.',
+          'group': 'pyro', 'level': 1,
+          }),
         # zmq services config
         ('zmq-repository-address',
          {'type' : 'string',
--- a/server/serverctl.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/server/serverctl.py	Mon Jan 21 18:01:25 2013 +0100
@@ -442,7 +442,7 @@
         config = ServerConfiguration.config_for(appid)
         try:
             system = config.sources()['system']
-            extra_args=system.get('db-extra-arguments')
+            extra_args = system.get('db-extra-arguments')
             extra = extra_args and {'extra_args': extra_args} or {}
             get_connection(
                 system['db-driver'], database=system['db-name'],
--- a/server/session.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/server/session.py	Mon Jan 21 18:01:25 2013 +0100
@@ -33,7 +33,6 @@
 
 from cubicweb import UnknownEid, QueryError, schema, server
 from cubicweb.req import RequestSessionBase
-from cubicweb.dbapi import ConnectionProperties
 from cubicweb.utils import make_uid
 from cubicweb.rqlrewrite import RQLRewriter
 from cubicweb.server import ShuttingDown
@@ -232,10 +231,8 @@
     def __init__(self, user, repo, cnxprops=None, _id=None):
         super(Session, self).__init__(repo.vreg)
         self.id = _id or make_uid(unormalize(user.login).encode('UTF8'))
-        cnxprops = cnxprops or ConnectionProperties('inmemory')
         self.user = user
         self.repo = repo
-        self.cnxtype = cnxprops.cnxtype
         self.timestamp = time()
         self.default_mode = 'read'
         # undo support
@@ -258,8 +255,8 @@
         self._closed_lock = threading.Lock()
 
     def __unicode__(self):
-        return '<%ssession %s (%s 0x%x)>' % (
-            self.cnxtype, unicode(self.user.login), self.id, id(self))
+        return '<session %s (%s 0x%x)>' % (
+            unicode(self.user.login), self.id, id(self))
 
     def transaction(self, free_cnxset=True):
         """return context manager to enter a transaction for the session: when
@@ -1185,7 +1182,6 @@
         super(InternalSession, self).__init__(InternalManager(), repo, cnxprops,
                                               _id='internal')
         self.user._cw = self # XXX remove when "vreg = user._cw.vreg" hack in entity.py is gone
-        self.cnxtype = 'inmemory'
         if not safe:
             self.disable_hook_categories('integrity')
 
--- a/server/test/unittest_repository.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/server/test/unittest_repository.py	Mon Jan 21 18:01:25 2013 +0100
@@ -36,7 +36,7 @@
                       UnknownEid, AuthenticationError, Unauthorized, QueryError)
 from cubicweb.predicates import is_instance
 from cubicweb.schema import CubicWebSchema, RQLConstraint
-from cubicweb.dbapi import connect, multiple_connections_unfix, ConnectionProperties
+from cubicweb.dbapi import connect, multiple_connections_unfix
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.devtools.repotest import tuplify
 from cubicweb.server import repository, hook
@@ -360,7 +360,8 @@
 
 
     def _pyro_client(self, done):
-        cnx = connect(self.repo.config.appid, u'admin', password='gingkow',
+        cnx = connect('pyro:///'+self.repo.config.appid,
+                      u'admin', password='gingkow',
                       initlog=False) # don't reset logging configuration
         try:
             cnx.load_appobjects(subpath=('entities',))
@@ -414,10 +415,8 @@
         srv.quit()
 
     def _zmq_client(self, done):
-        cnxprops = ConnectionProperties('zmq')
         try:
             cnx = connect('tcp://127.0.0.1:41415', u'admin', password=u'gingkow',
-                          cnxprops=cnxprops,
                           initlog=False) # don't reset logging configuration
             try:
                 cnx.load_appobjects(subpath=('entities',))
--- a/web/views/authentication.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/web/views/authentication.py	Mon Jan 21 18:01:25 2013 +0100
@@ -169,8 +169,7 @@
         raise AuthenticationError()
 
     def _authenticate(self, login, authinfo):
-        cnxprops = ConnectionProperties(self.vreg.config.repo_method,
-                                        close=False, log=self.log_queries)
+        cnxprops = ConnectionProperties(close=False, log=self.log_queries)
         cnx = repo_connect(self.repo, login, cnxprops=cnxprops, **authinfo)
         # decorate connection
         cnx.vreg = self.vreg
--- a/web/views/debug.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/web/views/debug.py	Mon Jan 21 18:01:25 2013 +0100
@@ -103,7 +103,7 @@
                    % (element, xml_escape(unicode(stats[element])),
                       element.endswith('percent') and '%' or '' ))
         w(u'</table>')
-        if req.cnx._cnxtype == 'inmemory' and req.user.is_in_group('managers'):
+        if req.cnx.is_repo_in_memory and req.user.is_in_group('managers'):
             w(u'<h3>%s</h3>' % _('opened sessions'))
             sessions = repo._sessions.values()
             if sessions:
--- a/web/webconfig.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/web/webconfig.py	Mon Jan 21 18:01:25 2013 +0100
@@ -84,6 +84,13 @@
     uiprops = {'FCKEDITOR_PATH': ''}
 
     options = merge_options(CubicWebConfiguration.options + (
+        ('repository-uri',
+         {'type' : 'string',
+          'default': 'inmemory://',
+          'help': 'see `cubicweb.dbapi.connect` documentation for possible value',
+          'group': 'web', 'level': 2,
+          }),
+
         ('anonymous-user',
          {'type' : 'string',
           'default': None,
@@ -238,10 +245,6 @@
                 continue
             yield key, pdef
 
-    # method used to connect to the repository: 'inmemory' / 'pyro'
-    # Pyro repository by default
-    repo_method = 'pyro'
-
     # don't use @cached: we want to be able to disable it while this must still
     # be cached
     def repository(self, vreg=None):
@@ -250,7 +253,7 @@
             return self.__repo
         except AttributeError:
             from cubicweb.dbapi import get_repository
-            repo = get_repository(self.repo_method, vreg=vreg, config=self)
+            repo = get_repository(config=self, vreg=vreg)
             self.__repo = repo
             return repo
 
--- a/web/webctl.py	Thu Jan 10 23:05:45 2013 +0100
+++ b/web/webctl.py	Mon Jan 21 18:01:25 2013 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -46,7 +46,7 @@
         if not automatic:
             print '\n' + underline_title('Generic web configuration')
             config = self.config
-            if config.repo_method == 'pyro' or config.pyro_enabled():
+            if config['repository-uri'].startswith('pyro://') or config.pyro_enabled():
                 print '\n' + underline_title('Pyro configuration')
                 config.input_config('pyro', inputlevel)
             config.input_config('web', inputlevel)