diff options
author | Diego Roversi <diegor@tiscali.it> | 2019-09-08 18:12:27 +0200 |
---|---|---|
committer | Diego Roversi <diegor@tiscali.it> | 2019-09-08 18:12:27 +0200 |
commit | 1d9925c287b318ec21343e2682b51ab6a36ae8db (patch) | |
tree | 17d1c0ac21eea6f291146520afa8381db4586fb4 /bubbob/statesaver.py |
initial commit from cvs 1.6.2
Diffstat (limited to 'bubbob/statesaver.py')
-rw-r--r-- | bubbob/statesaver.py | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/bubbob/statesaver.py b/bubbob/statesaver.py new file mode 100644 index 0000000..85d3425 --- /dev/null +++ b/bubbob/statesaver.py @@ -0,0 +1,135 @@ +""" +A pure Python implementation of statesaver.c that runs on top of PyPy. +See description in statesaver.c. +Difference: this supports new-style instances too. +Use statesaver.standard_build() as the inst_build() if you want. +""" + +from _pickle_support import generator_new +import types + +def standard_build(self): + if type(self) is types.InstanceType: + # old-style instance + return types.InstanceType(self.__class__) + else: + # new-style instance + return type(self).__new__(type(self)) + +# ____________________________________________________________ + +def not_copied(x, memo): + return x + +def copy_custom_instance(x, memo): + try: + return memo[id(x)] + except KeyError: + y = x.inst_build() + memo[id(x)] = y + for key, value in x.__dict__.items(): + y.__dict__[key] = copyrec(value, memo) + return y + +def copy_tuple(x, memo): + return tuple([copyrec(item, memo) for item in x]) + +def copy_list(x, memo): + try: + return memo[id(x)] + except KeyError: + y = [] + memo[id(x)] = y + for item in x: + y.append(copyrec(item, memo)) + return y + +def copy_dict(x, memo): + try: + return memo[id(x)] + except KeyError: + y = {} + memo[id(x)] = y + for key, value in x.items(): + y[copyrec(key, memo)] = copyrec(value, memo) + return y + +def copy_function(x, memo): + if not x.func_defaults: + return x # not copied + try: + return memo[id(x)] + except KeyError: + y = types.FunctionType(x.func_code, x.func_globals, x.func_name) + memo[id(x)] = y + y.func_defaults = copyrec(x.func_defaults, memo) + return y + +def copy_method(x, memo): + return types.MethodType(copyrec(x.im_func, memo), + copyrec(x.im_self, memo), + x.im_class) + +def copy_generator(x, memo): + try: + return memo[id(x)] + except KeyError: + y = generator_new(copyrec(x.gi_frame, memo), x.gi_running) + memo[id(x)] = y + return y + +def copy_frame(x, memo): + try: + return memo[id(x)] + except KeyError: + frame_new, args, state = x.__reduce__() + y = frame_new(*args) + memo[id(x)] = y + newstate = [] + for item in state: + if not (item is x.f_globals or item is x.f_builtins): + item = copyrec(item, memo) + newstate.append(item) + y.__setstate__(newstate) + return y + +def copy_seqiter(x, memo): + try: + return memo[id(x)] + except KeyError: + # XXX self-recursion is not correctly handled here + seqiter_new, args = x.__reduce__() + args = [copyrec(item, memo) for item in args] + y = seqiter_new(*args) + memo[id(x)] = y + return y + +# ____________________________________________________________ + +type_handlers = {tuple: copy_tuple, + list: copy_list, + dict: copy_dict, + types.FunctionType: copy_function, + types.MethodType: copy_method, + types.GeneratorType: copy_generator, + types.FrameType: copy_frame, + type(iter([])): copy_seqiter, + } + +def no_handler_found(x, memo): + if hasattr(x, '__dict__') and hasattr(x.__class__, 'inst_build'): + handler = copy_custom_instance + else: + handler = not_copied + type_handlers[x.__class__] = handler + return handler(x, memo) + +def copyrec(x, memo): + try: + cls = x.__class__ + except AttributeError: + return x # 'cls' is likely an old-style class object + return type_handlers.get(cls, no_handler_found)(x, memo) + +def copy(x): + return copyrec(x, {}) |