|
44 | 44 |
|
45 | 45 | import operator |
46 | 46 | import io |
| 47 | +import imp |
47 | 48 | import pickle |
48 | 49 | import struct |
49 | 50 | import sys |
@@ -134,8 +135,19 @@ def save_module(self, obj): |
134 | 135 | """ |
135 | 136 | Save a module as an import |
136 | 137 | """ |
| 138 | + mod_name = obj.__name__ |
| 139 | + # If module is successfully found then it is not a dynamically created module |
| 140 | + try: |
| 141 | + _find_module(mod_name) |
| 142 | + is_dynamic = False |
| 143 | + except ImportError: |
| 144 | + is_dynamic = True |
| 145 | + |
137 | 146 | self.modules.add(obj) |
138 | | - self.save_reduce(subimport, (obj.__name__,), obj=obj) |
| 147 | + if is_dynamic: |
| 148 | + self.save_reduce(dynamic_subimport, (obj.__name__, vars(obj)), obj=obj) |
| 149 | + else: |
| 150 | + self.save_reduce(subimport, (obj.__name__,), obj=obj) |
139 | 151 | dispatch[types.ModuleType] = save_module |
140 | 152 |
|
141 | 153 | def save_codeobject(self, obj): |
@@ -313,7 +325,7 @@ def extract_func_data(self, func): |
313 | 325 | return (code, f_globals, defaults, closure, dct, base_globals) |
314 | 326 |
|
315 | 327 | def save_builtin_function(self, obj): |
316 | | - if obj.__module__ is "__builtin__": |
| 328 | + if obj.__module__ == "__builtin__": |
317 | 329 | return self.save_global(obj) |
318 | 330 | return self.save_function(obj) |
319 | 331 | dispatch[types.BuiltinFunctionType] = save_builtin_function |
@@ -584,11 +596,20 @@ def save_file(self, obj): |
584 | 596 | self.save(retval) |
585 | 597 | self.memoize(obj) |
586 | 598 |
|
| 599 | + def save_ellipsis(self, obj): |
| 600 | + self.save_reduce(_gen_ellipsis, ()) |
| 601 | + |
| 602 | + def save_not_implemented(self, obj): |
| 603 | + self.save_reduce(_gen_not_implemented, ()) |
| 604 | + |
587 | 605 | if PY3: |
588 | 606 | dispatch[io.TextIOWrapper] = save_file |
589 | 607 | else: |
590 | 608 | dispatch[file] = save_file |
591 | 609 |
|
| 610 | + dispatch[type(Ellipsis)] = save_ellipsis |
| 611 | + dispatch[type(NotImplemented)] = save_not_implemented |
| 612 | + |
592 | 613 | """Special functions for Add-on libraries""" |
593 | 614 | def inject_addons(self): |
594 | 615 | """Plug in system. Register additional pickling functions if modules already loaded""" |
@@ -620,6 +641,12 @@ def subimport(name): |
620 | 641 | return sys.modules[name] |
621 | 642 |
|
622 | 643 |
|
| 644 | +def dynamic_subimport(name, vars): |
| 645 | + mod = imp.new_module(name) |
| 646 | + mod.__dict__.update(vars) |
| 647 | + sys.modules[name] = mod |
| 648 | + return mod |
| 649 | + |
623 | 650 | # restores function attributes |
624 | 651 | def _restore_attr(obj, attr): |
625 | 652 | for key, val in attr.items(): |
@@ -663,6 +690,11 @@ def _genpartial(func, args, kwds): |
663 | 690 | kwds = {} |
664 | 691 | return partial(func, *args, **kwds) |
665 | 692 |
|
| 693 | +def _gen_ellipsis(): |
| 694 | + return Ellipsis |
| 695 | + |
| 696 | +def _gen_not_implemented(): |
| 697 | + return NotImplemented |
666 | 698 |
|
667 | 699 | def _fill_function(func, globals, defaults, dict): |
668 | 700 | """ Fills in the rest of function data into the skeleton function object |
@@ -698,6 +730,18 @@ def _make_skel_func(code, closures, base_globals = None): |
698 | 730 | None, None, closure) |
699 | 731 |
|
700 | 732 |
|
| 733 | +def _find_module(mod_name): |
| 734 | + """ |
| 735 | + Iterate over each part instead of calling imp.find_module directly. |
| 736 | + This function is able to find submodules (e.g. sickit.tree) |
| 737 | + """ |
| 738 | + path = None |
| 739 | + for part in mod_name.split('.'): |
| 740 | + if path is not None: |
| 741 | + path = [path] |
| 742 | + file, path, description = imp.find_module(part, path) |
| 743 | + return file, path, description |
| 744 | + |
701 | 745 | """Constructors for 3rd party libraries |
702 | 746 | Note: These can never be renamed due to client compatibility issues""" |
703 | 747 |
|
|
0 commit comments