<gh_stars>0
"""
NetRef - transparent network references implementation.
"""
import sys
import inspect
import types
import cPickle as pickle

from rpyc.core import consts

_local_netref_attrs = frozenset([
    '____conn__', '____oid__', '__class__', '__cmp__', '__del__', '__delattr__', 
    '__dir__', '__doc__', '__getattr__', '__getattribute__', '__hash__', 
    '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', 
    '__reduce_ex__', '__repr__', '__setattr__', '__slots__', '__str__', 
    '__weakref__', '__dict__', '__members__', '__methods__',
])

_builtin_types = [
    type, object, types.InstanceType, types.ClassType, bool, complex, dict, 
    file, float, int, list, long, slice, str, basestring, tuple, unicode, 
    str, set, frozenset, Exception, types.NoneType, types.DictProxyType, 
    types.BuiltinFunctionType, types.GeneratorType, types.MethodType, 
    types.CodeType, types.FrameType, types.TracebackType, xrange,
    types.ModuleType, types.FunctionType,
    
    type(int.__add__),      # wrapper_descriptor
    type((1).__add__),      # method-wrapper
    type(iter([])),         # listiterator
    type(iter(())),         # tupleiterator
    type(iter(xrange(10))), # rangeiterator
    type(iter(set())),      # setiterator
]

_normalized_builtin_types = dict(((t.__name__, t.__module__), t) 
    for t in _builtin_types)

def syncreq(proxy, handler, *args):
    """performs a synchronous request on the given proxy object"""
    conn = object.__getattribute__(proxy, "____conn__")
    oid = object.__getattribute__(proxy, "____oid__")
    return conn().sync_request(handler, oid, *args)

def asyncreq(proxy, handler, *args):
    """performs an asynchronous request on the given proxy object, 
    retuning an AsyncResult"""
    conn = object.__getattribute__(proxy, "____conn__")
    oid = object.__getattribute__(proxy, "____oid__")
    return conn().async_request(handler, oid, *args)

class NetrefMetaclass(type):
    """a metaclass just to customize the __repr__ of netref classes"""
    __slots__ = ()
    def __repr__(self):
        if self.__module__:
            return "<netref class '%s.%s'>" % (self.__module__, self.__name__)
        else:
            return "<netref class '%s'>" % (self.__name__,)

class BaseNetref(object):
    """the base netref object, from which all netref classes derive"""
    __metaclass__ = NetrefMetaclass
    __slots__ = ["____conn__", "____oid__", "__weakref__"]

    def __init__(self, conn, oid):
        self.____conn__ = conn
        self.____oid__ = oid
    def __del__(self):
        try:
            asyncreq(self, consts.HANDLE_DEL)
        except Exception: 
            # raised in a destructor, most likely on program termination,
            # it's safe to ignore all exceptions here
            pass
    
    def __getattribute__(self, name):
        if name in _local_netref_attrs:
            if name == "__class__":
                cls = object.__getattribute__(self, "__class__")
                if cls is None:
                    cls = self.__getattr__("__class__")
                return cls
            elif name == "__doc__":
                return self.__getattr__("__doc__")
            elif name == "__members__":                       # for Python < 2.6
                return self.__dir__()
            else:
                return object.__getattribute__(self, name)
        elif name == "__call__":                          # IronPython issue #10
            return object.__getattribute__(self, "__call__")
        else:
            return syncreq(self, consts.HANDLE_GETATTR, name)
    def __getattr__(self, name):
        return syncreq(self, consts.HANDLE_GETATTR, name)
    def __delattr__(self, name):
        if name in _local_netref_attrs:
            object.__delattr__(self, name)
        else:
            syncreq(self, consts.HANDLE_DELATTR, name)
    def __setattr__(self, name, value):
        if name in _local_netref_attrs:
            object.__setattr__(self, name, value)
        else:
            syncreq(self, consts.HANDLE_SETATTR, name, value)
    def __dir__(self):
        return list(syncreq(self, consts.HANDLE_DIR))
    
    # support for metaclasses
    def __hash__(self):
        return syncreq(self, consts.HANDLE_HASH)
    def __cmp__(self, other):
        return syncreq(self, consts.HANDLE_CMP, other)
    def __repr__(self):
        return syncreq(self, consts.HANDLE_REPR)
    def __str__(self):
        return syncreq(self, consts.HANDLE_STR)
    # support for pickle
    def __reduce_ex__(self, proto):
        return pickle.loads, (syncreq(self, consts.HANDLE_PICKLE, proto),)

def _make_method(name, doc):
    name = str(name)                                      # IronPython issue #10
    if name == "__call__":
        def __call__(_self, *args, **kwargs):
            kwargs = tuple(kwargs.items())
            return syncreq(_self, consts.HANDLE_CALL, args, kwargs)
        __call__.__doc__ = doc
        return __call__
    else:
        def method(_self, *args, **kwargs):
            kwargs = tuple(kwargs.items())
            return syncreq(_self, consts.HANDLE_CALLATTR, name, args, kwargs)
        method.__name__ = name
        method.__doc__ = doc
        return method

def inspect_methods(obj):
    """returns a list of (method name, docstring) tuples of all the methods of 
    the given object"""
    methods = {}
    attrs = {}
    if isinstance(obj, type):
        # don't forget the darn metaclass
        mros = list(reversed(type(obj).__mro__)) + list(reversed(obj.__mro__)) 
    else:
        mros = reversed(type(obj).__mro__)
    for basecls in mros:
        attrs.update(basecls.__dict__)
    for name, attr in attrs.iteritems():
        if name not in _local_netref_attrs and hasattr(attr, "__call__"):
            methods[name] = inspect.getdoc(attr)
    return methods.items()

def class_factory(clsname, modname, methods):
    clsname = str(clsname)                                # IronPython issue #10
    modname = str(modname)                                # IronPython issue #10    
    ns = {"__slots__" : ()}
    for name, doc in methods:
        name = str(name)                                  # IronPython issue #10
        if name not in _local_netref_attrs:
            ns[name] = _make_method(name, doc)
    ns["__module__"] = modname
    if modname in sys.modules and hasattr(sys.modules[modname], clsname):
        ns["__class__"] = getattr(sys.modules[modname], clsname)
    elif (clsname, modname) in _normalized_builtin_types:
        ns["__class__"] = _normalized_builtin_types[clsname, modname]
    else:
        # to be resolved by the instance
        ns["__class__"] = None
    return type(clsname, (BaseNetref,), ns)

builtin_classes_cache = {}
for cls in _builtin_types:
    builtin_classes_cache[cls.__name__, cls.__module__] = class_factory(
        cls.__name__, cls.__module__, inspect_methods(cls))

"""
NetRef - transparent network references implementation.
"""
import sys
import inspect
import types
import cPickle as pickle

from rpyc.core import consts

_local_netref_attrs = frozenset([
    '____conn__', '____oid__', '__class__', '__cmp__', '__del__', '__delattr__', 
    '__dir__', '__doc__', '__getattr__', '__getattribute__', '__hash__', 
    '__init__', '__metaclass__', '__module__', '__new__', '__reduce__', 
    '__reduce_ex__', '__repr__', '__setattr__', '__slots__', '__str__', 
    '__weakref__', '__dict__', '__members__', '__methods__',
])

_builtin_types = [
    type, object, types.InstanceType, types.ClassType, bool, complex, dict, 
    file, float, int, list, long, slice, str, basestring, tuple, unicode, 
    str, set, frozenset, Exception, types.NoneType, types.DictProxyType, 
    types.BuiltinFunctionType, types.GeneratorType, types.MethodType, 
    types.CodeType, types.FrameType, types.TracebackType, xrange,
    types.ModuleType, types.FunctionType,
    
    type(int.__add__),      # wrapper_descriptor
    type((1).__add__),      # method-wrapper
    type(iter([])),         # listiterator
    type(iter(())),         # tupleiterator
    type(iter(xrange(10))), # rangeiterator
    type(iter(set())),      # setiterator
]

_normalized_builtin_types = dict(((t.__name__, t.__module__), t) 
    for t in _builtin_types)

def syncreq(proxy, handler, *args):
    """performs a synchronous request on the given proxy object"""
    conn = object.__getattribute__(proxy, "____conn__")
    oid = object.__getattribute__(proxy, "____oid__")
    return conn().sync_request(handler, oid, *args)

def asyncreq(proxy, handler, *args):
    """performs an asynchronous request on the given proxy object, 
    retuning an AsyncResult"""
    conn = object.__getattribute__(proxy, "____conn__")
    oid = object.__getattribute__(proxy, "____oid__")
    return conn().async_request(handler, oid, *args)

class NetrefMetaclass(type):
    """a metaclass just to customize the __repr__ of netref classes"""
    __slots__ = ()
    def __repr__(self):
        if self.__module__:
            return "<netref class '%s.%s'>" % (self.__module__, self.__name__)
        else:
            return "<netref class '%s'>" % (self.__name__,)

class BaseNetref(object):
    """the base netref object, from which all netref classes derive"""
    __metaclass__ = NetrefMetaclass
    __slots__ = ["____conn__", "____oid__", "__weakref__"]

    def __init__(self, conn, oid):
        self.____conn__ = conn
        self.____oid__ = oid
    def __del__(self):
        try:
            asyncreq(self, consts.HANDLE_DEL)
        except Exception: 
            # raised in a destructor, most likely on program termination,
            # it's safe to ignore all exceptions here
            pass
    
    def __getattribute__(self, name):
        if name in _local_netref_attrs:
            if name == "__class__":
                cls = object.__getattribute__(self, "__class__")
                if cls is None:
                    cls = self.__getattr__("__class__")
                return cls
            elif name == "__doc__":
                return self.__getattr__("__doc__")
            elif name == "__members__":                       # for Python < 2.6
                return self.__dir__()
            else:
                return object.__getattribute__(self, name)
        elif name == "__call__":                          # IronPython issue #10
            return object.__getattribute__(self, "__call__")
        else:
            return syncreq(self, consts.HANDLE_GETATTR, name)
    def __getattr__(self, name):
        return syncreq(self, consts.HANDLE_GETATTR, name)
    def __delattr__(self, name):
        if name in _local_netref_attrs:
            object.__delattr__(self, name)
        else:
            syncreq(self, consts.HANDLE_DELATTR, name)
    def __setattr__(self, name, value):
        if name in _local_netref_attrs:
            object.__setattr__(self, name, value)
        else:
            syncreq(self, consts.HANDLE_SETATTR, name, value)
    def __dir__(self):
        return list(syncreq(self, consts.HANDLE_DIR))
    
    # support for metaclasses
    def __hash__(self):
        return syncreq(self, consts.HANDLE_HASH)
    def __cmp__(self, other):
        return syncreq(self, consts.HANDLE_CMP, other)
    def __repr__(self):
        return syncreq(self, consts.HANDLE_REPR)
    def __str__(self):
        return syncreq(self, consts.HANDLE_STR)
    # support for pickle
    def __reduce_ex__(self, proto):
        return pickle.loads, (syncreq(self, consts.HANDLE_PICKLE, proto),)

def _make_method(name, doc):
    name = str(name)                                      # IronPython issue #10
    if name == "__call__":
        def __call__(_self, *args, **kwargs):
            kwargs = tuple(kwargs.items())
            return syncreq(_self, consts.HANDLE_CALL, args, kwargs)
        __call__.__doc__ = doc
        return __call__
    else:
        def method(_self, *args, **kwargs):
            kwargs = tuple(kwargs.items())
            return syncreq(_self, consts.HANDLE_CALLATTR, name, args, kwargs)
        method.__name__ = name
        method.__doc__ = doc
        return method

def inspect_methods(obj):
    """returns a list of (method name, docstring) tuples of all the methods of 
    the given object"""
    methods = {}
    attrs = {}
    if isinstance(obj, type):
        # don't forget the darn metaclass
        mros = list(reversed(type(obj).__mro__)) + list(reversed(obj.__mro__)) 
    else:
        mros = reversed(type(obj).__mro__)
    for basecls in mros:
        attrs.update(basecls.__dict__)
    for name, attr in attrs.iteritems():
        if name not in _local_netref_attrs and hasattr(attr, "__call__"):
            methods[name] = inspect.getdoc(attr)
    return methods.items()

def class_factory(clsname, modname, methods):
    clsname = str(clsname)                                # IronPython issue #10
    modname = str(modname)                                # IronPython issue #10    
    ns = {"__slots__" : ()}
    for name, doc in methods:
        name = str(name)                                  # IronPython issue #10
        if name not in _local_netref_attrs:
            ns[name] = _make_method(name, doc)
    ns["__module__"] = modname
    if modname in sys.modules and hasattr(sys.modules[modname], clsname):
        ns["__class__"] = getattr(sys.modules[modname], clsname)
    elif (clsname, modname) in _normalized_builtin_types:
        ns["__class__"] = _normalized_builtin_types[clsname, modname]
    else:
        # to be resolved by the instance
        ns["__class__"] = None
    return type(clsname, (BaseNetref,), ns)

builtin_classes_cache = {}
for cls in _builtin_types:
    builtin_classes_cache[cls.__name__, cls.__module__] = class_factory(
        cls.__name__, cls.__module__, inspect_methods(cls))
NetRef - transparent network references implementation. # wrapper_descriptor # method-wrapper # listiterator # tupleiterator # rangeiterator # setiterator performs a synchronous request on the given proxy object performs an asynchronous request on the given proxy object,      retuning an AsyncResult a metaclass just to customize the __repr__ of netref classes the base netref object, from which all netref classes derive # raised in a destructor, most likely on program termination, # it's safe to ignore all exceptions here # for Python < 2.6 # IronPython issue #10 # support for metaclasses # support for pickle # IronPython issue #10 returns a list of (method name, docstring) tuples of all the methods of      the given object # don't forget the darn metaclass # IronPython issue #10 # IronPython issue #10 # IronPython issue #10 # to be resolved by the instance