Author: Armin Rigo <[email protected]>
Branch: py3k
Changeset: r86326:fc46cb0e02ed
Date: 2016-08-19 09:59 +0200
http://bitbucket.org/pypy/pypy/changeset/fc46cb0e02ed/
Log: I *think* this expresses the logic that we want more cleanly
diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py
--- a/pypy/interpreter/mixedmodule.py
+++ b/pypy/interpreter/mixedmodule.py
@@ -19,6 +19,7 @@
""" NOT_RPYTHON """
Module.__init__(self, space, w_name)
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 = []
@@ -57,22 +58,11 @@
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_all=False):
- # Because setdictvalue is unable to immediately load all attributes
- # (due to an importlib bootstrapping problem), this method needs to be
- # able to support saving the content of a module's dict without
- # requiring that the entire dict already be loaded. To support that
- # properly, when updating the dict, we must be careful to never
- # overwrite the value of a key already in w_initialdict. (So as to
avoid
- # overriding the builtin value with a user-provided value)
- if self.space.is_none(self.w_initialdict) or save_all:
- self.w_initialdict = self.space.call_method(self.w_dict, 'copy')
- else:
- w_items = self.space.call_method(self.w_dict, 'items')
- for w_item in self.space.iteriterable(w_items):
- w_key, w_value = self.space.fixedview(w_item,
expected_length=2)
- if not self.space.contains_w(self.w_initialdict, w_key):
- self.space.setitem(self.w_initialdict, w_key, w_value)
+ 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
def get_applevel_name(cls):
@@ -101,9 +91,13 @@
return w_value
def setdictvalue(self, space, attr, w_value):
- if self.lazy:
- self._load_lazily(space, attr)
- self.save_module_content_for_future_reload()
+ 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
@@ -137,11 +131,23 @@
def getdict(self, space):
if self.lazy:
+ # 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().
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
return self.w_dict
def _cleanup_(self):
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
@@ -131,7 +131,7 @@
@unwrap_spec(w_module=MixedModule)
def save_module_content_for_future_reload(space, w_module):
- w_module.save_module_content_for_future_reload(save_all=True)
+ w_module.save_module_content_for_future_reload()
def set_code_callback(space, w_callable):
cache = space.fromcache(CodeHookCache)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit