Remove the remote repository-access-through-zmq support

Modern methods such as the rqlcontroller cube + the cwclientlib library are the way forward.

Closes #2919297.

authorAurelien Campeas <aurelien.campeas@logilab.fr>
changesetef3059a692cb
branchdefault
phasepublic
hiddenno
parent revision#684215aca046 Remove remote repository-access-through-pyro support
child revision#1e030b1a5622 Remove leftover bits from start-repository command, and document its demise
files modified by this revision
dbapi.py
doc/3.21.rst
hooks/zmq.py
repoapi.py
server/cwzmq.py
server/serverconfig.py
server/serverctl.py
server/test/unittest_repository.py
test/unittest_utils.py
utils.py
zmqclient.py
# HG changeset patch
# User Aurelien Campeas <aurelien.campeas@logilab.fr>
# Date 1426252240 -3600
# Fri Mar 13 14:10:40 2015 +0100
# Node ID ef3059a692cb92ae405daf6ad9243e645b64a972
# Parent 684215aca046b3b458e4cadc6b337f4a79a2dc12
Remove the remote repository-access-through-zmq support

Modern methods such as the rqlcontroller cube + the cwclientlib library are the way forward.

Closes #2919297.

diff --git a/dbapi.py b/dbapi.py
@@ -116,24 +116,21 @@
1 
2      `database` may be:
3 
4      * a simple instance id for in-memory connection
5 
6 -    * a uri like scheme://host:port/instanceid where scheme may be one of
7 -      'inmemory' or 'zmqpickle'
8 -
9 -      * if scheme is handled by ZMQ (eg 'tcp'), you should not specify an
10 -        instance id
11 +    * a uri like scheme://host:port/instanceid where scheme must be
12 +      'inmemory'
13 
14      Other arguments:
15 
16      :login:
17        the user login to use to authenticate.
18 
19      :cnxprops:
20        a :class:`ConnectionProperties` instance, allowing to specify
21 -      the connection method (eg in memory or zmq).
22 +      the connection method (eg in memory).
23 
24      :setvreg:
25        flag telling if a registry should be initialized for the connection.
26        Don't change this unless you know what you're doing.
27 
@@ -148,40 +145,22 @@
28        where it's already initialized.
29 
30      :kwargs:
31        there goes authentication tokens. You usually have to specify a password
32        for the given user, using a named 'password' argument.
33 +
34      """
35      if not urlparse(database).scheme:
36          warn('[3.16] give an qualified URI as database instead of using '
37               'host/cnxprops to specify the connection method',
38               DeprecationWarning, stacklevel=2)
39 -        if cnxprops and cnxprops.cnxtype == 'zmq':
40 -            database = kwargs.pop('host')
41 -        elif cnxprops and cnxprops.cnxtype == 'inmemory':
42 -            database = 'inmemory://' + database
43      puri = urlparse(database)
44      method = puri.scheme.lower()
45 -    if method == 'inmemory':
46 -        config = cwconfig.instance_configuration(puri.netloc)
47 -    else:
48 -        config = cwconfig.CubicWebNoAppConfiguration()
49 +    assert method == 'inmemory'
50 +    config = cwconfig.instance_configuration(puri.netloc)
51      repo = get_repository(database, config=config)
52 -    if method == 'inmemory':
53 -        vreg = repo.vreg
54 -    elif setvreg:
55 -        if mulcnx:
56 -            multiple_connections_fix()
57 -        vreg = cwvreg.CWRegistryStore(config, initlog=initlog)
58 -        schema = repo.get_schema()
59 -        for oldetype, newetype in ETYPE_NAME_MAP.items():
60 -            if oldetype in schema:
61 -                print 'aliasing', newetype, 'to', oldetype
62 -                schema._entities[newetype] = schema._entities[oldetype]
63 -        vreg.set_schema(schema)
64 -    else:
65 -        vreg = None
66 +    vreg = repo.vreg
67      cnx = _repo_connect(repo, login, cnxprops=cnxprops, **kwargs)
68      cnx.vreg = vreg
69      return cnx
70 
71  def in_memory_repo(config):
diff --git a/doc/3.21.rst b/doc/3.21.rst
@@ -13,8 +13,8 @@
72  ---------------------
73 
74  * the user_callback api has been removed; people should use plain
75    ajax functions instead
76 
77 -* the Pyro remote repository access method has been entirely removed
78 -  (emerging alternatives such as rqlcontroller and cwclientlib should
79 -  be used instead)
80 +* the `Pyro` and `Zmq-pickle` remote repository access methods have
81 +  been entirely removed (emerging alternatives such as rqlcontroller
82 +  and cwclientlib should be used instead)
diff --git a/hooks/zmq.py b/hooks/zmq.py
@@ -1,7 +1,7 @@
83  # -*- coding: utf-8 -*-
84 -# copyright 2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
85 +# copyright 2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
86  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
87  #
88  # This file is part of CubicWeb.
89  #
90  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -48,32 +48,5 @@
91          for address in address_sub:
92              self.repo.app_instances_bus.add_subscriber(address)
93          self.repo.app_instances_bus.start()
94 
95 
96 -class ZMQRepositoryServerStopHook(hook.Hook):
97 -    __regid__ = 'zmqrepositoryserverstop'
98 -    events = ('server_shutdown',)
99 -
100 -    def __call__(self):
101 -        server = getattr(self.repo, 'zmq_repo_server', None)
102 -        if server:
103 -            self.repo.zmq_repo_server.quit()
104 -
105 -class ZMQRepositoryServerStartHook(hook.Hook):
106 -    __regid__ = 'zmqrepositoryserverstart'
107 -    events = ('server_startup',)
108 -
109 -    def __call__(self):
110 -        config = self.repo.config
111 -        if config.name == 'repository':
112 -            # start-repository command already starts a zmq repo
113 -            return
114 -        address = config.get('zmq-repository-address')
115 -        if not address:
116 -            return
117 -        self.repo.warning('remote access to the repository via zmq/pickle is deprecated')
118 -        from cubicweb.server import cwzmq
119 -        self.repo.zmq_repo_server = server = cwzmq.ZMQRepositoryServer(self.repo)
120 -        server.connect(address)
121 -        self.repo.threaded_task(server.run)
122 -
diff --git a/repoapi.py b/repoapi.py
@@ -50,15 +50,11 @@
123 
124      if protocol == 'inmemory':
125          # me may have been called with a dummy 'inmemory://' uri ...
126          return _get_inmemory_repo(config, vreg)
127 
128 -    if protocol.startswith('zmqpickle-'):
129 -        from cubicweb.zmqclient import ZMQRepositoryClient
130 -        return ZMQRepositoryClient(uri)
131 -    else:
132 -        raise ConnectionError('unknown protocol: `%s`' % protocol)
133 +    raise ConnectionError('unknown protocol: `%s`' % protocol)
134 
135  def connect(repo, login, **kwargs):
136      """Take credential and return associated ClientConnection.
137 
138      The ClientConnection is associated to a new Session object that will be
diff --git a/server/cwzmq.py b/server/cwzmq.py
@@ -1,7 +1,7 @@
139  # -*- coding: utf-8 -*-
140 -# copyright 2012-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
141 +# copyright 2012-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
142  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
143  #
144  # This file is part of CubicWeb.
145  #
146  # CubicWeb is free software: you can redistribute it and/or modify it under the
@@ -15,74 +15,21 @@
147  # details.
148  #
149  # You should have received a copy of the GNU Lesser General Public License along
150  # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
151 
152 -import cPickle
153 -import traceback
154 -from time import localtime, mktime
155  from threading import Thread
156  from logging import getLogger
157 
158  import zmq
159  from zmq.eventloop import ioloop
160  import zmq.eventloop.zmqstream
161 
162  from cubicweb import set_log_methods
163 
164 -ctx = zmq.Context()
165 -
166 -def cwproto_to_zmqaddr(address):
167 -    """ converts a cw-zmq address (like zmqpickle-tcp://<ip>:<port>)
168 -    into a proper zmq address (tcp://<ip>:<port>)
169 -    """
170 -    assert address.startswith('zmqpickle-'), 'bad protocol string %s' % address
171 -    return address.split('-', 1)[1] # chop the `zmqpickle-` prefix
172 -
173 -
174 -class Finished(Exception):
175 -    """raise to remove an event from the event loop"""
176 -
177 -class TimeEvent:
178 -    """base event"""
179 -    # timefunc = staticmethod(localtime)
180 -    timefunc = localtime
181 -
182 -    def __init__(self, absolute=None, period=None):
183 -        # local time tuple
184 -        if absolute is None:
185 -            absolute = self.timefunc()
186 -        self.absolute = absolute
187 -        # optional period in seconds
188 -        self.period = period
189 
190 -    def is_ready(self):
191 -        """return  true if the event is ready to be fired"""
192 -        now = self.timefunc()
193 -        if self.absolute <= now:
194 -            return True
195 -        return False
196 -
197 -    def fire(self, server):
198 -        """fire the event
199 -        must be overridden by concrete events
200 -        """
201 -        raise NotImplementedError()
202 -
203 -    def update(self):
204 -        """update the absolute date for the event or raise a finished exception
205 -        """
206 -        if self.period is None:
207 -            raise Finished
208 -        self.absolute = localtime(mktime(self.absolute) + self.period)
209 -
210 -
211 -class QuitEvent(TimeEvent):
212 -    """stop the server"""
213 -    def fire(self, server):
214 -        server.repo.shutdown()
215 -        server.quiting = True
216 +ctx = zmq.Context()
217 
218 
219  class ZMQComm(object):
220      """
221      A simple ZMQ-based notification bus.
@@ -177,134 +124,7 @@
222      def subscribe(self, topic, callback):
223          self.dispatch_table[topic] = callback
224          self.ioloop.add_callback(lambda: self.stream.setsockopt(zmq.SUBSCRIBE, topic))
225 
226 
227 -class ZMQRepositoryServer(object):
228 -
229 -    def __init__(self, repository):
230 -        """make the repository available as a PyRO object"""
231 -        self.address = None
232 -        self.repo = repository
233 -        self.socket = None
234 -        self.stream = None
235 -        self.loop = ioloop.IOLoop()
236 -
237 -        # event queue
238 -        self.events = []
239 -
240 -    def connect(self, address):
241 -        self.address = cwproto_to_zmqaddr(address)
242 -
243 -    def run(self):
244 -        """enter the service loop"""
245 -        # start repository looping tasks
246 -        self.socket = ctx.socket(zmq.REP)
247 -        self.stream = zmq.eventloop.zmqstream.ZMQStream(self.socket, io_loop=self.loop)
248 -        self.stream.bind(self.address)
249 -        self.info('ZMQ server bound on: %s', self.address)
250 -
251 -        self.stream.on_recv(self.process_cmds)
252 -
253 -        try:
254 -            self.loop.start()
255 -        except zmq.ZMQError:
256 -            self.warning('ZMQ event loop killed')
257 -        self.quit()
258 -
259 -    def trigger_events(self):
260 -        """trigger ready events"""
261 -        for event in self.events[:]:
262 -            if event.is_ready():
263 -                self.info('starting event %s', event)
264 -                event.fire(self)
265 -                try:
266 -                    event.update()
267 -                except Finished:
268 -                    self.events.remove(event)
269 -
270 -    def process_cmd(self, cmd):
271 -        """Delegate the given command to the repository.
272 -
273 -        ``cmd`` is a list of (method_name, args, kwargs)
274 -        where ``args`` is a list of positional arguments
275 -        and ``kwargs`` is a dictionnary of named arguments.
276 -
277 -        >>> rset = delegate_to_repo(["execute", [sessionid], {'rql': rql}])
278 -
279 -        :note1: ``kwargs`` may be ommited
280 -
281 -            >>> rset = delegate_to_repo(["execute", [sessionid, rql]])
282 -
283 -        :note2: both ``args`` and ``kwargs`` may be omitted
284 -
285 -            >>> schema = delegate_to_repo(["get_schema"])
286 -            >>> schema = delegate_to_repo("get_schema") # also allowed
287 -
288 -        """
289 -        cmd = cPickle.loads(cmd)
290 -        if not cmd:
291 -            raise AttributeError('function name required')
292 -        if isinstance(cmd, basestring):
293 -            cmd = [cmd]
294 -        if len(cmd) < 2:
295 -            cmd.append(())
296 -        if len(cmd) < 3:
297 -            cmd.append({})
298 -        cmd  = list(cmd) + [(), {}]
299 -        funcname, args, kwargs = cmd[:3]
300 -        result = getattr(self.repo, funcname)(*args, **kwargs)
301 -        return result
302 -
303 -    def process_cmds(self, cmds):
304 -        """Callback intended to be used with ``on_recv``.
305 -
306 -        Call ``delegate_to_repo`` on each command and send a pickled of
307 -        each result recursively.
308 -
309 -        Any exception are catched, pickled and sent.
310 -        """
311 -        try:
312 -            for cmd in cmds:
313 -                result = self.process_cmd(cmd)
314 -                self.send_data(result)
315 -        except Exception as exc:
316 -            traceback.print_exc()
317 -            self.send_data(exc)
318 -
319 -    def send_data(self, data):
320 -        self.socket.send_pyobj(data)
321 -
322 -    def quit(self, shutdown_repo=False):
323 -        """stop the server"""
324 -        self.info('Quitting ZMQ server')
325 -        try:
326 -            self.loop.add_callback(self.loop.stop)
327 -            self.stream.on_recv(None)
328 -            self.stream.close()
329 -        except Exception as e:
330 -            print e
331 -            pass
332 -        if shutdown_repo and not self.repo.shutting_down:
333 -            event = QuitEvent()
334 -            event.fire(self)
335 -
336 -    # server utilitities ######################################################
337 -
338 -    def install_sig_handlers(self):
339 -        """install signal handlers"""
340 -        import signal
341 -        self.info('installing signal handlers')
342 -        signal.signal(signal.SIGINT, lambda x, y, s=self: s.quit(shutdown_repo=True))
343 -        signal.signal(signal.SIGTERM, lambda x, y, s=self: s.quit(shutdown_repo=True))
344 -
345 -
346 -    # these are overridden by set_log_methods below
347 -    # only defining here to prevent pylint from complaining
348 -    @classmethod
349 -    def info(cls, msg, *a, **kw):
350 -        pass
351 -
352 -
353  set_log_methods(Publisher, getLogger('cubicweb.zmq.pub'))
354  set_log_methods(Subscriber, getLogger('cubicweb.zmq.sub'))
355 -set_log_methods(ZMQRepositoryServer, getLogger('cubicweb.zmq.repo'))
diff --git a/server/serverconfig.py b/server/serverconfig.py
@@ -195,18 +195,10 @@
356            'default': (),
357            'help': 'comma separated list of email addresses that will be \
358  notified of every changes.',
359            'group': 'email', 'level': 2,
360            }),
361 -        # zmq services config
362 -        ('zmq-repository-address',
363 -         {'type' : 'string',
364 -          'default': None,
365 -          'help': ('ZMQ URI on which the repository will be bound '
366 -                   'to (of the form `zmqpickle-tcp://<ipaddr>:<port>`).'),
367 -          'group': 'zmq', 'level': 3,
368 -          }),
369           ('zmq-address-sub',
370            {'type' : 'csv',
371             'default' : None,
372             'help': ('List of ZMQ addresses to subscribe to (requires pyzmq) '
373                      '(of the form `tcp://<ipaddr>:<port>`)'),
diff --git a/server/serverctl.py b/server/serverctl.py
@@ -36,11 +36,10 @@
374 
375  from cubicweb import AuthenticationError, ExecutionError, ConfigurationError
376  from cubicweb.toolsutils import Command, CommandHandler, underline_title
377  from cubicweb.cwctl import CWCTL, check_options_consistency, ConfigureInstanceCommand
378  from cubicweb.server import SOURCE_TYPES
379 -from cubicweb.server.repository import Repository
380  from cubicweb.server.serverconfig import (
381      USER_OPTIONS, ServerConfiguration, SourceConfiguration,
382      ask_source_config, generate_source_config)
383 
384  # utility functions ###########################################################
@@ -674,76 +673,10 @@
385              cnx.commit()
386              print '-> password reset, sources file regenerated.'
387          cnx.close()
388 
389 
390 -class StartRepositoryCommand(Command):
391 -    """Start a CubicWeb RQL server for a given instance.
392 -
393 -    The server will be remotely accessible through ZMQ
394 -
395 -    <instance>
396 -      the identifier of the instance to initialize.
397 -    """
398 -    name = 'start-repository'
399 -    arguments = '<instance>'
400 -    min_args = max_args = 1
401 -    options = (
402 -        ('debug',
403 -         {'short': 'D', 'action' : 'store_true',
404 -          'help': 'start server in debug mode.'}),
405 -        ('loglevel',
406 -         {'short': 'l', 'type' : 'choice', 'metavar': '<log level>',
407 -          'default': None, 'choices': ('debug', 'info', 'warning', 'error'),
408 -          'help': 'debug if -D is set, error otherwise',
409 -          }),
410 -        ('address',
411 -         {'short': 'a', 'type': 'string', 'metavar': '<protocol>://<host>:<port>',
412 -          'default': '',
413 -          'help': ('specify a ZMQ URI on which to bind'),
414 -          }),
415 -        )
416 -
417 -    def create_repo(self, config):
418 -        address = self['address']
419 -        if not address:
420 -            address = config.get('zmq-repository-address')
421 -        from cubicweb.server.utils import TasksManager
422 -        from cubicweb.server.cwzmq import ZMQRepositoryServer
423 -        repo = Repository(config, TasksManager())
424 -        return ZMQRepositoryServer(repo), address
425 -
426 -    def run(self, args):
427 -        from logilab.common.daemon import daemonize, setugid
428 -        from cubicweb.cwctl import init_cmdline_log_threshold
429 -        print 'WARNING: Standalone repository with pyro or zmq access is deprecated'
430 -        appid = args[0]
431 -        debug = self['debug']
432 -        if sys.platform == 'win32' and not debug:
433 -            logger = logging.getLogger('cubicweb.ctl')
434 -            logger.info('Forcing debug mode on win32 platform')
435 -            debug = True
436 -        config = ServerConfiguration.config_for(appid, debugmode=debug)
437 -        init_cmdline_log_threshold(config, self['loglevel'])
438 -        # create the server
439 -        server, address = self.create_repo(config)
440 -        # ensure the directory where the pid-file should be set exists (for
441 -        # instance /var/run/cubicweb may be deleted on computer restart)
442 -        pidfile = config['pid-file']
443 -        piddir = os.path.dirname(pidfile)
444 -        # go ! (don't daemonize in debug mode)
445 -        if not os.path.exists(piddir):
446 -            os.makedirs(piddir)
447 -        if not debug and daemonize(pidfile, umask=config['umask']):
448 -            return
449 -        uid = config['uid']
450 -        if uid is not None:
451 -            setugid(uid)
452 -        server.install_sig_handlers()
453 -        server.connect(address)
454 -        server.run()
455 -
456 
457  def _remote_dump(host, appid, output, sudo=False):
458      # XXX generate unique/portable file name
459      from datetime import date
460      filename = '%s-%s.tgz' % (appid, date.today().strftime('%Y-%m-%d'))
@@ -1123,11 +1056,10 @@
461          schema_diff(fsschema, repo.schema, permissionshandler, diff_tool, ignore=('eid',))
462 
463 
464  for cmdclass in (CreateInstanceDBCommand, InitInstanceCommand,
465                   GrantUserOnInstanceCommand, ResetAdminPasswordCommand,
466 -                 StartRepositoryCommand,
467                   DBDumpCommand, DBRestoreCommand, DBCopyCommand,
468                   AddSourceCommand, CheckRepositoryCommand, RebuildFTICommand,
469                   SynchronizeSourceCommand, SchemaDiffCommand,
470                   ):
471      CWCTL.register(cmdclass)
diff --git a/server/test/unittest_repository.py b/server/test/unittest_repository.py
@@ -29,14 +29,13 @@
472 
473  from cubicweb import (BadConnectionId, ValidationError,
474                        UnknownEid, AuthenticationError, Unauthorized, QueryError)
475  from cubicweb.predicates import is_instance
476  from cubicweb.schema import RQLConstraint
477 -from cubicweb.dbapi import connect, multiple_connections_unfix
478  from cubicweb.devtools.testlib import CubicWebTC
479  from cubicweb.devtools.repotest import tuplify
480 -from cubicweb.server import repository, hook
481 +from cubicweb.server import hook
482  from cubicweb.server.sqlutils import SQL_PREFIX
483  from cubicweb.server.hook import Hook
484  from cubicweb.server.sources import native
485  from cubicweb.server.session import SessionClosedError
486 
@@ -310,68 +309,10 @@
487          self.assertEqual(cstr.expression, 'O final TRUE')
488 
489          ownedby = schema.rschema('owned_by')
490          self.assertEqual(ownedby.objects('CWEType'), ('CWUser',))
491 
492 -    def test_zmq(self):
493 -        try:
494 -            import zmq
495 -        except ImportError:
496 -            self.skipTest("zmq in not available")
497 -        done = []
498 -        from cubicweb.devtools import TestServerConfiguration as ServerConfiguration
499 -        from cubicweb.server.cwzmq import ZMQRepositoryServer
500 -        # the client part has to be in a thread due to sqlite limitations
501 -        t = threading.Thread(target=self._zmq_client, args=(done,))
502 -        t.start()
503 -
504 -        zmq_server = ZMQRepositoryServer(self.repo)
505 -        zmq_server.connect('zmqpickle-tcp://127.0.0.1:41415')
506 -
507 -        t2 = threading.Thread(target=self._zmq_quit, args=(done, zmq_server,))
508 -        t2.start()
509 -
510 -        zmq_server.run()
511 -
512 -        t2.join(1)
513 -        t.join(1)
514 -
515 -        self.assertTrue(done[0])
516 -
517 -        if t.isAlive():
518 -            self.fail('something went wrong, thread still alive')
519 -
520 -    def _zmq_quit(self, done, srv):
521 -        while not done:
522 -            time.sleep(0.1)
523 -        srv.quit()
524 -
525 -    def _zmq_client(self, done):
526 -        try:
527 -            cnx = connect('zmqpickle-tcp://127.0.0.1:41415', u'admin', password=u'gingkow',
528 -                          initlog=False) # don't reset logging configuration
529 -            try:
530 -                cnx.load_appobjects(subpath=('entities',))
531 -                # check we can get the schema
532 -                schema = cnx.get_schema()
533 -                self.assertTrue(cnx.vreg)
534 -                self.assertTrue('etypes'in cnx.vreg)
535 -                cu = cnx.cursor()
536 -                rset = cu.execute('Any U,G WHERE U in_group G')
537 -                user = iter(rset.entities()).next()
538 -                self.assertTrue(user._cw)
539 -                self.assertTrue(user._cw.vreg)
540 -                from cubicweb.entities import authobjs
541 -                self.assertIsInstance(user._cw.user, authobjs.CWUser)
542 -                cnx.close()
543 -                done.append(True)
544 -            finally:
545 -                # connect monkey patch some method by default, remove them
546 -                multiple_connections_unfix()
547 -        finally:
548 -            done.append(False)
549 -
550      def test_internal_api(self):
551          repo = self.repo
552          cnxid = repo.connect(self.admlogin, password=self.admpassword)
553          session = repo._get_session(cnxid, setcnxset=True)
554          self.assertEqual(repo.type_and_source_from_eid(2, session),
diff --git a/test/unittest_utils.py b/test/unittest_utils.py
@@ -56,12 +56,10 @@
555      def test_parse_repo_uri(self):
556          self.assertEqual(('inmemory', None, 'myapp'),
557                           parse_repo_uri('myapp'))
558          self.assertEqual(('inmemory', None, 'myapp'),
559                           parse_repo_uri('inmemory://myapp'))
560 -        self.assertEqual(('zmqpickle-tcp', '127.0.0.1:666', ''),
561 -                         parse_repo_uri('zmqpickle-tcp://127.0.0.1:666'))
562          with self.assertRaises(NotImplementedError):
563              parse_repo_uri('foo://bar')
564 
565 
566 
diff --git a/utils.py b/utils.py
@@ -605,20 +605,17 @@
567 
568  def parse_repo_uri(uri):
569      """ transform a command line uri into a (protocol, hostport, appid), e.g:
570      <myapp>                      -> 'inmemory', None, '<myapp>'
571      inmemory://<myapp>           -> 'inmemory', None, '<myapp>'
572 -    zmqpickle://[host][:port]    -> 'zmqpickle', 'host:port', None
573      """
574      parseduri = urlparse(uri)
575      scheme = parseduri.scheme
576      if scheme == '':
577          return ('inmemory', None, parseduri.path)
578      if scheme == 'inmemory':
579          return (scheme, None, parseduri.netloc)
580 -    if scheme.startswith('zmqpickle-'):
581 -        return (scheme, parseduri.netloc, parseduri.path)
582      raise NotImplementedError('URI protocol not implemented for `%s`' % uri)
583 
584 
585 
586  logger = getLogger('cubicweb.utils')
diff --git a/zmqclient.py b/zmqclient.py
@@ -1,64 +0,0 @@
587 -# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
588 -# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
589 -#
590 -# This file is part of CubicWeb.
591 -#
592 -# CubicWeb is free software: you can redistribute it and/or modify it under the
593 -# terms of the GNU Lesser General Public License as published by the Free
594 -# Software Foundation, either version 2.1 of the License, or (at your option)
595 -# any later version.
596 -#
597 -# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
598 -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
599 -# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
600 -# details.
601 -#
602 -# You should have received a copy of the GNU Lesser General Public License along
603 -# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
604 -"""Source to query another RQL repository using ZMQ"""
605 -
606 -__docformat__ = "restructuredtext en"
607 -_ = unicode
608 -
609 -from functools import partial
610 -import zmq
611 -
612 -from cubicweb.server.cwzmq import cwproto_to_zmqaddr
613 -
614 -# XXX hack to overpass old zmq limitation that force to have
615 -# only one context per python process
616 -try:
617 -    from cubicweb.server.cwzmq import ctx
618 -except ImportError:
619 -    ctx = zmq.Context()
620 -
621 -class ZMQRepositoryClient(object):
622 -    """
623 -    This class delegates the overall repository stuff to a remote source.
624 -
625 -    So calling a method of this repository will result on calling the
626 -    corresponding method of the remote source repository.
627 -
628 -    Any raised exception on the remote source is propagated locally.
629 -
630 -    ZMQ is used as the transport layer and cPickle is used to serialize data.
631 -    """
632 -
633 -    def __init__(self, zmq_address):
634 -        """A zmq address provided here will be like
635 -        `zmqpickle-tcp://127.0.0.1:42000`.  W
636 -
637 -        We chop the prefix to get a real zmq address.
638 -        """
639 -        self.socket = ctx.socket(zmq.REQ)
640 -        self.socket.connect(cwproto_to_zmqaddr(zmq_address))
641 -
642 -    def __zmqcall__(self, name, *args, **kwargs):
643 -         self.socket.send_pyobj([name, args, kwargs])
644 -         result = self.socket.recv_pyobj()
645 -         if isinstance(result, BaseException):
646 -             raise result
647 -         return result
648 -
649 -    def __getattr__(self, name):
650 -        return partial(self.__zmqcall__, name)