diff --git a/rpyc/core/protocol.py b/rpyc/core/protocol.py index d7a90f61..d31b2eca 100644 --- a/rpyc/core/protocol.py +++ b/rpyc/core/protocol.py @@ -336,8 +336,8 @@ def _unbox(self, package): # boxing return self._local_objects[value] if label == consts.LABEL_REMOTE_REF: id_pack = (str(value[0]), value[1], value[2]) # so value is a id_pack - if id_pack in self._proxy_cache: - proxy = self._proxy_cache[id_pack] + proxy = self._proxy_cache.get(id_pack) + if proxy is not None: proxy.____refcount__ += 1 # if cached then remote incremented refcount, so sync refcount else: proxy = self._netref_factory(id_pack) diff --git a/rpyc/core/stream.py b/rpyc/core/stream.py index 859faafb..fb8baaa4 100644 --- a/rpyc/core/stream.py +++ b/rpyc/core/stream.py @@ -326,7 +326,10 @@ def from_std(cls): :returns: a :class:`PipeStream` instance """ - return cls(sys.stdin, sys.stdout) + pipestream = cls(sys.stdin, sys.stdout) + sys.stdin = os.open(os.devnull, os.O_RDWR) + sys.stdout = sys.stdin + return pipestream @classmethod def create_pair(cls): @@ -405,7 +408,10 @@ def __init__(self, incoming, outgoing): @classmethod def from_std(cls): - return cls(sys.stdin, sys.stdout) + pipestream = cls(sys.stdin, sys.stdout) + sys.stdin = os.open(os.devnull, os.O_RDWR) + sys.stdout = sys.stdin + return pipestream @classmethod def create_pair(cls): diff --git a/rpyc/lib/__init__.py b/rpyc/lib/__init__.py index 88f1a59e..93aff1b0 100644 --- a/rpyc/lib/__init__.py +++ b/rpyc/lib/__init__.py @@ -170,44 +170,65 @@ def exp_backoff(collision): def get_id_pack(obj): - """introspects the given "local" object, returns id_pack as expected by BaseNetref + """introspects the given "local" object, returns id_pack as expected by + BaseNetref - The given object is "local" in the sense that it is from the local cache. Any object in the local cache exists - in the current address space or is a netref. A netref in the local cache could be from a chained-connection. - To handle type related behavior properly, the attribute `__class__` is a descriptor for netrefs. + The given object is "local" in the sense that it is from the local + cache. Any object in the local cache exists in the current address + space or is a netref. A netref in the local cache could be from a + chained-connection. To handle type related behavior properly, the + attribute `__class__` is a descriptor for netrefs. - So, check thy assumptions regarding the given object when creating `id_pack`. + So, check thy assumptions regarding the given object when creating + `id_pack`. """ - if hasattr(obj, '____id_pack__'): - # netrefs are handled first since __class__ is a descriptor - return obj.____id_pack__ - elif inspect.ismodule(obj) or getattr(obj, '__name__', None) == 'module': - # TODO: not sure about this, need to enumerate cases in units + undef = object() + name_pack = getattr(obj, '____id_pack__', undef) + if name_pack is not undef: + return name_pack + + obj_name = getattr(obj, '__name__', None) + if (inspect.ismodule(obj) or obj_name == 'module'): if isinstance(obj, type): # module obj_cls = type(obj) - name_pack = '{0}.{1}'.format(obj_cls.__module__, obj_cls.__name__) + name_pack = ( + f'{obj_cls.__module__}.{obj_cls.__name__}' + ) return (name_pack, id(type(obj)), id(obj)) + + if inspect.ismodule(obj) and obj_name != 'module': + if obj_name in sys.modules: + name_pack = obj_name + else: + obj_cls = getattr(obj, '__class__', type(obj)) + name_pack = ( + f'{obj_cls.__module__}.{obj_name}' + ) + elif inspect.ismodule(obj): + name_pack = ( + f'{obj.__module__}.{obj_name}' + ) else: - if inspect.ismodule(obj) and obj.__name__ != 'module': - if obj.__name__ in sys.modules: - name_pack = obj.__name__ - else: - name_pack = '{0}.{1}'.format(obj.__class__.__module__, obj.__name__) - elif inspect.ismodule(obj): - name_pack = '{0}.{1}'.format(obj.__module__, obj.__name__) - print(name_pack) - elif hasattr(obj, '__module__'): - name_pack = '{0}.{1}'.format(obj.__module__, obj.__name__) + obj_module = getattr(obj, '__module__', undef) + if obj_module is not undef: + name_pack = ( + f'{obj.__module__}.{obj_name}' + ) else: - obj_cls = type(obj) - name_pack = '{0}'.format(obj.__name__) - return (name_pack, id(type(obj)), id(obj)) - elif not inspect.isclass(obj): - name_pack = '{0}.{1}'.format(obj.__class__.__module__, obj.__class__.__name__) + name_pack = obj_name return (name_pack, id(type(obj)), id(obj)) - else: - name_pack = '{0}.{1}'.format(obj.__module__, obj.__name__) - return (name_pack, id(obj), 0) + + if not inspect.isclass(obj): + obj_cls = getattr(obj, '__class__', type(obj)) + name_pack = ( + f'{obj_cls.__module__}.{obj_cls.__name__}' + ) + return (name_pack, id(type(obj)), id(obj)) + + name_pack = ( + f'{obj.__module__}.{obj_name}' + ) + return (name_pack, id(obj), 0) def get_methods(obj_attrs, obj): @@ -229,6 +250,6 @@ def get_methods(obj_attrs, obj): for basecls in mros: attrs.update(basecls.__dict__) for name, attr in attrs.items(): - if name not in obj_attrs and hasattr(attr, "__call__"): + if name not in obj_attrs and inspect.isroutine(attr): methods[name] = inspect.getdoc(attr) return methods.items()