[issue20854] multiprocessing.managers.Server: problem with returning proxy of registered object

Allis Tauri report at bugs.python.org
Sun Mar 9 10:24:15 CET 2014


Allis Tauri added the comment:

Thanks for the suggestion. 
method_to_typeid and create_method are documented features, so I don't see why not. It does the trick in a cleaner way than my workaround: a metaclass for MyClass that just checks the arguments before creating a new instance. It just seems to me somewhat counterintuitive.

Another issue that arises in my case is: when I try to pass a proxy of MyClass to a subprocess it looses its' _manager during pickling and thus the ability to create proxies for children returned by get_child. This is solved by reimplementing the (not-working: http://bugs.python.org/issue5862) __reduce__ method of BaseManager in MyManager and creating corresponding custom proxy for MyClass with __reduce__ method also reimplemented.


So the working solution for the situation is:

either
1.1)
class ReturnProxy(type):
    def __call__(cls, *args, **kwargs):
        if not kwargs and args and isinstance(args[0], cls):
            return args[0]
        return super(ReturnProxy, cls).__call__(*args, **kwargs)

class MyClass(object):
    __metaclass__ = ReturnProxy
    ###class body###

or
1.2)
Your solution with the second typeid registration.

2)
class AutoProxyMeta(type):
    '''Metaclass that replicates multiprocessing.managers.MakeProxyType
    functionality, but allows proxy classes that use it to be pickable'''
    def __new__(cls, name, bases, attrs):
        dic = {}
        for meth in attrs.get('_exposed_', ()):
            exec '''def %s(self, *args, **kwds):
            return self._callmethod(%r, args, kwds)''' % (meth, meth) in dic
        dic.update(attrs)
        return super(AutoProxyMeta, cls).__new__(cls, name, bases, dic)
        
class MyClassProxy(BaseProxy):
    __metaclass__ = AutoProxyMeta
    _exposed_ = ('get_child',)
    _method_to_typeid_ = dict(get_child='MyClass')
    #or: _method_to_typeid_ = dict(get_child='_MyClass')
    
    def __reduce__(self):
        _unpickle, (cls, token, serializer, kwds) = BaseProxy.__reduce__(self)
        kwds['manager'] = self._manager
        return _unpickle, (cls, token, serializer, kwds)

class MyClassManager(UManager):
    def __reduce__(self):
        return (RebuildMyClassManager,
                (self._address, None, self._serializer))
WorkCounterManager.register('MyClass', MyClass, MyClassProxy)
#optionally: WorkCounterManager.register('_MyClass', None, MyClassProxy, create_method=False)

def RebuildMyClassManager(address, authkey, serializer):
    mgr = MyClassManager(address, authkey, serializer)
    mgr.connect()
    return mgr

----------

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue20854>
_______________________________________


More information about the Python-bugs-list mailing list