From 0025775659a9ec6c52ef460c6fff0d6f37a052ff Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Thu, 13 Mar 2014 22:06:32 -0500 Subject: just pretend attributes of unimportable lazy modules don't exist Suggested by Diana Clarke. --- CHANGES | 2 ++ documentation/index.rst | 10 +++++----- six.py | 23 ++++++++++++++--------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index f9d3530..3dae7cb 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,8 @@ This file lists the changes in each six version. Development version ------------------- +- Raise an AttributeError for every attribute of unimportable modules. + - Issue #56: Make the fake modules six.moves puts into sys.modules appear not to have a __path__ unless they are loaded. diff --git a/documentation/index.rst b/documentation/index.rst index 99e82e1..3d7828b 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -450,11 +450,11 @@ functionality; its structure mimics the structure of the Python 3 interpreter. For example, ``sys.modules["six.moves.winreg"].LoadKey`` would fail on any non-Windows platform. Unfortunately, some applications try to load attributes on every module in :data:`py3:sys.modules`. six mitigates - this problem for some applications by pretending ``__file__`` and - ``__name__`` don't exist on lazy modules that aren't loaded. That doesn't - work in every case, though. If you are encountering this problem and don't - use any from imports directly from ``six.moves`` modules, you can workaround - the issue by removing the six proxy modules:: + this problem for some applications by pretending attributes on unimportable + modules don't exist. This hack doesn't work in every case, though. If you are + encountering problems with the lazy modules and don't use any from imports + directly from ``six.moves`` modules, you can workaround the issue by removing + the six proxy modules:: d = [name for name in sys.modules if name.startswith("six.moves.")] for name in d: diff --git a/six.py b/six.py index 58cb95b..c86dc98 100644 --- a/six.py +++ b/six.py @@ -105,17 +105,22 @@ class MovedModule(_LazyDescr): return _import_module(self.mod) def __getattr__(self, attr): - # Hack around the Django autoreloader. The reloader tries to get - # __file__ or __name__ of every module in sys.modules. This doesn't work - # well if this MovedModule is for an module that is unavailable on this - # machine (like winreg on Unix systems). Thus, we pretend __file__ and - # __name__ don't exist if the module hasn't been loaded yet. We give - # __path__ the same treatment for Google AppEngine. See issues #51, #53 - # and #56. + # It turns out many Python frameworks like to traverse sys.modules and + # try to load various attributes. This causes problems if this is a + # platform-specific module on the wrong platform, like _winreg on + # Unixes. Therefore, we silently pretend unimportable modules do not + # have any attributes. See issues #51, #53, #56, and #63 for the full + # tales of woe. + # + # First, if possible, avoid loading the module just to look at __file__, + # __name__, or __path__. if (attr in ("__file__", "__name__", "__path__") and self.mod not in sys.modules): - raise AttributeError - _module = self._resolve() + raise AttributeError(attr) + try: + _module = self._resolve() + except ImportError: + raise AttributeError(attr) value = getattr(_module, attr) setattr(self, attr, value) return value -- cgit v1.2.1