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