[pypy-commit] pypy py3.5: Backed out changeset f80cb4368b95

rlamy pypy.commits at gmail.com
Sat Oct 21 08:53:57 EDT 2017


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.5
Changeset: r92812:142c785bb994
Date: 2017-10-21 13:53 +0100
http://bitbucket.org/pypy/pypy/changeset/142c785bb994/

Log:	Backed out changeset f80cb4368b95

diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -574,6 +574,10 @@
             except ValueError:
                 pass      # ignore "2 is not a valid file descriptor"
 
+    if we_are_translated():
+        import __pypy__
+        __pypy__.save_module_content_for_future_reload(sys)
+
     mainmodule = type(sys)('__main__')
     sys.modules['__main__'] = mainmodule
 
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -515,8 +515,9 @@
                 # patcher relies on this behaviour.
                 w_mod2 = Module(self, w_name)
                 self.setitem(w_modules, w_name, w_mod2)
-                w_dict = w_mod.getdict(self)  # unlazy
-                self.call_method(w_mod2.getdict(self), 'update', w_dict)
+                w_mod.getdict(self)  # unlazy w_initialdict
+                self.call_method(w_mod2.getdict(self), 'update',
+                                 w_mod.w_initialdict)
                 return w_mod2
             self.setitem(w_modules, w_name, w_mod)
             w_mod.init(self)
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -10,7 +10,11 @@
 
 class MixedModule(Module):
     applevel_name = None
-    initialized = False
+
+    # The following attribute is None as long as the module has not been
+    # imported yet, and when it has been, it is mod.__dict__.copy() just
+    # after startup().
+    w_initialdict = None
     lazy = False
     submodule_name = None
 
@@ -19,6 +23,7 @@
         Module.__init__(self, space, w_name)
         init_extra_module_attrs(space, self)
         self.lazy = True
+        self.lazy_initial_values_w = {}
         self.__class__.buildloaders()
         self.loaders = self.loaders.copy()    # copy from the class to the inst
         self.submodules_w = []
@@ -42,14 +47,27 @@
     def init(self, space):
         """This is called each time the module is imported or reloaded
         """
+        if self.w_initialdict is not None:
+            # the module was already imported.  Refresh its content with
+            # the saved dict, as done with built-in and extension modules
+            # on CPython.
+            space.call_method(self.w_dict, 'update', self.w_initialdict)
+
         for w_submodule in self.submodules_w:
             name = space.text0_w(w_submodule.w_name)
             space.setitem(self.w_dict, space.newtext(name.split(".")[-1]), w_submodule)
             space.getbuiltinmodule(name)
 
-        if not self.initialized:
+        if self.w_initialdict is None:
             Module.init(self, space)
-            self.initialized = True
+            if not self.lazy and self.w_initialdict is None:
+                self.save_module_content_for_future_reload()
+
+    def save_module_content_for_future_reload(self):
+        # Save the current dictionary in w_initialdict, for future
+        # reloads.  This forces the dictionary if needed.
+        w_dict = self.getdict(self.space)
+        self.w_initialdict = self.space.call_method(w_dict, 'copy')
 
     @classmethod
     @not_rpython
@@ -78,6 +96,13 @@
         return w_value
 
     def setdictvalue(self, space, attr, w_value):
+        if self.lazy and attr not in self.lazy_initial_values_w:
+            # in lazy mode, the first time an attribute changes,
+            # we save away the old (initial) value.  This allows
+            # a future getdict() call to build the correct
+            # self.w_initialdict, containing the initial value.
+            w_initial_value = self._load_lazily(space, attr)
+            self.lazy_initial_values_w[attr] = w_initial_value
         space.setitem_str(self.w_dict, attr, w_value)
         return True
 
@@ -117,11 +142,23 @@
 
     def _force_lazy_dict_now(self):
         # Force the dictionary by calling all lazy loaders now.
+        # This also saves in self.w_initialdict a copy of all the
+        # initial values, including if they have already been
+        # modified by setdictvalue().
         space = self.space
         for name in self.loaders:
             w_value = self.get(name)
             space.setitem(self.w_dict, space.new_interned_str(name), w_value)
         self.lazy = False
+        self.save_module_content_for_future_reload()
+        for key, w_initial_value in self.lazy_initial_values_w.items():
+            w_key = space.new_interned_str(key)
+            if w_initial_value is not None:
+                space.setitem(self.w_initialdict, w_key, w_initial_value)
+            else:
+                if space.finditem(self.w_initialdict, w_key) is not None:
+                    space.delitem(self.w_initialdict, w_key)
+        del self.lazy_initial_values_w
 
     def _cleanup_(self):
         self.getdict(self.space)
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -92,6 +92,8 @@
         'set_debug'                 : 'interp_magic.set_debug',
         'locals_to_fast'            : 'interp_magic.locals_to_fast',
         'set_code_callback'         : 'interp_magic.set_code_callback',
+        'save_module_content_for_future_reload':
+                          'interp_magic.save_module_content_for_future_reload',
         'decode_long'               : 'interp_magic.decode_long',
         '_promote'                   : 'interp_magic._promote',
         'normalize_exc'             : 'interp_magic.normalize_exc',
@@ -129,7 +131,7 @@
                 raise
             else:
                 pass   # ok fine to ignore in this case
-
+        
         if self.space.config.translation.jit:
             features = detect_cpu.getcpufeatures(model)
             self.extra_interpdef('jit_backend_features',
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -145,6 +145,10 @@
     assert isinstance(w_frame, PyFrame)
     w_frame.locals2fast()
 
+ at unwrap_spec(w_module=MixedModule)
+def save_module_content_for_future_reload(space, w_module):
+    w_module.save_module_content_for_future_reload()
+
 def set_code_callback(space, w_callable):
     cache = space.fromcache(CodeHookCache)
     if space.is_none(w_callable):
diff --git a/pypy/module/__pypy__/test/test_magic.py b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -2,6 +2,18 @@
 class AppTestMagic:
     spaceconfig = dict(usemodules=['__pypy__'])
 
+    def test_save_module_content_for_future_reload(self):
+        import sys, __pypy__, imp
+        d = sys.dont_write_bytecode
+        sys.dont_write_bytecode = "hello world"
+        __pypy__.save_module_content_for_future_reload(sys)
+        sys.dont_write_bytecode = d
+        imp.reload(sys)
+        assert sys.dont_write_bytecode == "hello world"
+        #
+        sys.dont_write_bytecode = d
+        __pypy__.save_module_content_for_future_reload(sys)
+
     def test_new_code_hook(self):
         # workaround for running on top of old CPython 2.7 versions
         def exec_(code, d):


More information about the pypy-commit mailing list