def _export_codeobj(cobj): consts2 = [] for const in cobj.co_consts: if brine.dumpable(const): consts2.append(const) elif isinstance(const, CodeType): consts2.append(_export_codeobj(const)) else: raise TypeError( "Cannot export a function with non-brinable constants: %r" % (const, )) if is_py3k: exported = (cobj.co_argcount, cobj.co_kwonlyargcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) else: exported = (cobj.co_argcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) assert brine.dumpable(exported) return (CODEOBJ_MAGIC, exported)
def dump(typ, val, tb, include_local_traceback): if type(typ) is str: return typ if typ is StopIteration: return consts.EXC_STOP_ITERATION # optimization if include_local_traceback: tbtext = "".join(traceback.format_exception(typ, val, tb)) else: tbtext = "<traceback denied>" attrs = [] args = [] for name in dir(val): if name == "args": for a in val.args: if brine.dumpable(a): args.append(a) else: args.append(repr(a)) elif not name.startswith("_") or name == "_remote_tb": attrval = getattr(val, name) if not brine.dumpable(attrval): attrval = repr(attrval) attrs.append((name, attrval)) return (typ.__module__, typ.__name__), tuple(args), tuple(attrs), tbtext
def _export_codeobj(cobj): consts2 = [] for const in cobj.co_consts: if brine.dumpable(const): consts2.append(const) elif isinstance(const, CodeType): consts2.append(_export_codeobj(const)) else: raise TypeError( "Cannot export a function with non-brinable constants: %r" % (const, )) for op, arg in decode_codeobj(cobj): if op in ("LOAD_GLOBAL", "STORE_GLOBAL", "DELETE_GLOBAL"): if arg not in __builtin__.__dict__: raise TypeError( "Cannot export a function with non-builtin globals: %r" % (arg, )) if is_py3k: exported = (cobj.co_argcount, cobj.co_kwonlyargcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) else: exported = (cobj.co_argcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) assert brine.dumpable(exported) return (CODEOBJ_MAGIC, exported)
def _export_codeobj(cobj): consts2 = [] for const in cobj.co_consts: if brine.dumpable(const): consts2.append(const) elif isinstance(const, CodeType): consts2.append(_export_codeobj(const)) else: raise TypeError("Cannot export a function with non-brinable constants: %r" % (const,)) for op, arg in decode_codeobj(cobj): if op in ("LOAD_GLOBAL", "STORE_GLOBAL", "DELETE_GLOBAL"): if arg not in __builtin__.__dict__: raise TypeError("Cannot export a function with non-builtin globals: %r" % (arg,)) if is_py3k: exported = (cobj.co_argcount, cobj.co_kwonlyargcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) else: exported = (cobj.co_argcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) assert brine.dumpable(exported) return (CODEOBJ_MAGIC, exported)
def _export_codeobj(cobj): consts2 = [] for const in cobj.co_consts: if brine.dumpable(const): consts2.append(const) elif isinstance(const, CodeType): consts2.append(_export_codeobj(const)) else: raise TypeError( f"Cannot export a function with non-brinable constants: {const!r}" ) if is_py_gte38: # Constructor was changed in 3.8 to support "advanced" programming styles exported = (cobj.co_argcount, cobj.co_posonlyargcount, cobj.co_kwonlyargcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) else: exported = (cobj.co_argcount, cobj.co_kwonlyargcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) assert brine.dumpable(exported) return (CODEOBJ_MAGIC, exported)
def dump(typ, val, tb, include_local_traceback, include_local_version): """Dumps the given exceptions info, as returned by ``sys.exc_info()`` :param typ: the exception's type (class) :param val: the exceptions' value (instance) :param tb: the exception's traceback (a ``traceback`` object) :param include_local_traceback: whether or not to include the local traceback in the dumped info. This may expose the other side to implementation details (code) and package structure, and may theoretically impose a security risk. :returns: A tuple of ``((module name, exception name), arguments, attributes, traceback text)``. This tuple can be safely passed to :func:`brine.dump <rpyc.core.brine.dump>` """ if typ is StopIteration: return consts.EXC_STOP_ITERATION # optimization if type(typ) is str: return typ if include_local_traceback: tbtext = "".join(traceback.format_exception(typ, val, tb)) else: tbtext = "<traceback denied>" attrs = [] args = [] ignored_attrs = frozenset(["_remote_tb", "with_traceback"]) for name in dir(val): if name == "args": for a in val.args: if brine.dumpable(a): args.append(a) else: args.append(repr(a)) elif name.startswith("_") or name in ignored_attrs: continue else: try: attrval = getattr(val, name) except AttributeError: # skip this attr. see issue #108 continue if not brine.dumpable(attrval): attrval = repr(attrval) attrs.append((name, attrval)) if include_local_version: attrs.append(("_remote_version", version.version_string)) else: attrs.append(("_remote_version", "<version denied>")) return (typ.__module__, typ.__name__), tuple(args), tuple(attrs), tbtext
def test_brine(): x = ("he", 7, u"llo", 8, (), 900, None, True, Ellipsis, 18.2, 18.2j + 13, slice(1, 2, 3), frozenset([5, 6, 7]), NotImplemented, (1, 2)) assert dumpable(x) y = dump(x) z = load(y) assert x == z
def export_function(func): closure = func.__closure__ code = func.__code__ defaults = func.__defaults__ kwdefaults = func.__kwdefaults__ if kwdefaults is not None: kwdefaults = tuple(kwdefaults.items()) if closure: raise TypeError("Cannot export a function closure") if not brine.dumpable(defaults): raise TypeError("Cannot export a function with non-brinable defaults (__defaults__)") if not brine.dumpable(kwdefaults): raise TypeError("Cannot export a function with non-brinable defaults (__kwdefaults__)") return func.__name__, func.__module__, defaults, kwdefaults, _export_codeobj(code)[1]
def test_brine(): x = ("he", 7, u"llo", 8, (), 900, None, True, Ellipsis, 18.2, 18.2j + 13, slice(1, 2, 3), frozenset([5, 6, 7]), NotImplemented, (1,2)) assert dumpable(x) y = dump(x) z = load(y) assert x == z
def dump(typ, val, tb, include_local_traceback): """Dumps the given exceptions info, as returned by ``sys.exc_info()`` :param typ: the exception's type (class) :param val: the exceptions' value (instance) :param tb: the exception's traceback (a ``traceback`` object) :param include_local_traceback: whether or not to include the local traceback in the dumped info. This may expose the other side to implementation details (code) and package structure, and may theoretically impose a security risk. :returns: A tuple of ``((module name, exception name), arguments, attributes, traceback text)``. This tuple can be safely passed to :func:`brine.dump <rpyc.core.brine.dump>` """ if typ is StopIteration: return consts.EXC_STOP_ITERATION # optimization if type(typ) is str: return typ if include_local_traceback: tbtext = "".join(traceback.format_exception(typ, val, tb)) else: tbtext = "<traceback denied>" attrs = [] args = [] ignored_attrs = frozenset(["_remote_tb", "with_traceback"]) for name in dir(val): if name == "args": for a in val.args: if brine.dumpable(a): args.append(a) else: args.append(repr(a)) elif name.startswith("_") or name in ignored_attrs: continue else: try: attrval = getattr(val, name) except AttributeError: # skip this attr. see issue #108 continue if not brine.dumpable(attrval): attrval = repr(attrval) attrs.append((name, attrval)) return (typ.__module__, typ.__name__), tuple(args), tuple(attrs), tbtext
def export_function(func): func_closure = func.__closure__ func_code = func.__code__ func_defaults = func.__defaults__ if func_closure: raise TypeError("Cannot export a function closure") if not brine.dumpable(func_defaults): raise TypeError("Cannot export a function with non-brinable defaults (func_defaults)") return func.__name__, func.__module__, func_defaults, _export_codeobj(func_code)[1]
def test_brine_2(self): if is_py3k: exec('''x = (b"he", 7, "llo", 8, (), 900, None, True, Ellipsis, 18.2, 18.2j + 13, slice(1, 2, 3), frozenset([5, 6, 7]), NotImplemented, (1,2))''', globals()) else: exec('''x = ("he", 7, u"llo", 8, (), 900, None, True, Ellipsis, 18.2, 18.2j + 13, slice(1, 2, 3), frozenset([5, 6, 7]), NotImplemented, (1,2))''') self.assertTrue(brine.dumpable(x)) y = brine.dump(x) z = brine.load(y) self.assertEqual(x, z)
def _export_codeobj(cobj): consts2 = [] for const in cobj.co_consts: if brine.dumpable(const): consts2.append(const) elif isinstance(const, CodeType): consts2.append(_export_codeobj(const)) else: raise TypeError("Cannot export a function with non-brinable constants: %r" % (const,)) if is_py3k: exported = (cobj.co_argcount, cobj.co_kwonlyargcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) else: exported = (cobj.co_argcount, cobj.co_nlocals, cobj.co_stacksize, cobj.co_flags, cobj.co_code, tuple(consts2), cobj.co_names, cobj.co_varnames, cobj.co_filename, cobj.co_name, cobj.co_firstlineno, cobj.co_lnotab, cobj.co_freevars, cobj.co_cellvars) assert brine.dumpable(exported) return (CODEOBJ_MAGIC, exported)
def _box(self, obj): # boxing """store a local object in such a way that it could be recreated on the remote party either by-value or by-reference""" if brine.dumpable(obj): return consts.LABEL_VALUE, obj if type(obj) is tuple: return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj) elif isinstance(obj, netref.BaseNetref) and obj.____conn__ is self: return consts.LABEL_LOCAL_REF, obj.____id_pack__ else: id_pack = get_id_pack(obj) self._local_objects.add(id_pack, obj) return consts.LABEL_REMOTE_REF, id_pack
def _box(self, obj): """store a local object in such a way that it could be recreated on the remote party either by-value or by-reference""" if brine.dumpable(obj): return consts.LABEL_VALUE, obj if type(obj) is tuple: return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj) elif isinstance(obj, netref.BaseNetref) and obj.____conn__() is self: return consts.LABEL_LOCAL_REF, obj.____oid__ else: self._local_objects.add(obj) cls = getattr(obj, "__class__", type(obj)) return consts.LABEL_REMOTE_REF, (id(obj), cls.__name__, cls.__module__)
def export_function(func): if is_py3k: func_closure = func.__closure__ func_code = func.__code__ func_defaults = func.__defaults__ else: func_closure = func.func_closure func_code = func.func_code func_defaults = func.func_defaults if func_closure: raise TypeError("Cannot export a function closure") if not brine.dumpable(func_defaults): raise TypeError("Cannot export a function with non-brinable defaults (func_defaults)") return func.__name__, func.__module__, func_defaults, _export_codeobj(func_code)[1]
def _box(self, obj): # boxing """store a local object in such a way that it could be recreated on the remote party either by-value or by-reference""" if brine.dumpable(obj): return consts.LABEL_VALUE, obj if type(obj) is tuple: return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj) elif isinstance(obj, netref.BaseNetref) and obj.____conn__ is self: return consts.LABEL_LOCAL_REF, obj.____oid__ else: self._local_objects.add(obj) try: cls = obj.__class__ except Exception: # see issue #16 cls = type(obj) if not isinstance(cls, type): cls = type(obj) return consts.LABEL_REMOTE_REF, (id(obj), cls.__name__, cls.__module__)
def _box(self, obj): """store a local object in such a way that it could be recreated on the remote party either by-value or by-reference""" if brine.dumpable(obj): return consts.LABEL_VALUE, obj if type(obj) is tuple: return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj) elif isinstance(obj, netref.BaseNetref) and obj.____conn__() is self: return consts.LABEL_LOCAL_REF, obj.____oid__ elif isinstance(obj, AsyncResult): obj.async_set_expiry(3) # HACK: wait at most 3 seconds until the async result arrives return self._box(obj.async_value) else: self._local_objects.add(obj) try: cls = obj.__class__ except Exception: # see issue #16 cls = type(obj) return consts.LABEL_REMOTE_REF, (id(obj), cls.__name__, cls.__module__)
def _box(self, obj): """store a local object in such a way that it could be recreated on the remote party either by-value or by-reference""" if brine.dumpable(obj): return consts.LABEL_VALUE, obj if type(obj) is tuple: return consts.LABEL_TUPLE, tuple(self._box(item) for item in obj) elif isinstance(obj, netref.BaseNetref) and obj.____conn__() is self: return consts.LABEL_LOCAL_REF, obj.____oid__ elif isinstance(obj, AsyncResult): obj.async_set_expiry( 3 ) # HACK: wait at most 3 seconds until the async result arrives return self._box(obj.async_value) else: self._local_objects.add(obj) try: cls = obj.__class__ except Exception: # see issue #16 cls = type(obj) return consts.LABEL_REMOTE_REF, (id(obj), cls.__name__, cls.__module__)