This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author allista
Recipients allista, sbt
Date 2014-03-09.09:24:12
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1394357055.59.0.336905890049.issue20854@psf.upfronthosting.co.za>
In-reply-to
Content
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
History
Date User Action Args
2014-03-09 09:24:15allistasetrecipients: + allista, sbt
2014-03-09 09:24:15allistasetmessageid: <1394357055.59.0.336905890049.issue20854@psf.upfronthosting.co.za>
2014-03-09 09:24:15allistalinkissue20854 messages
2014-03-09 09:24:12allistacreate