changeset 32448:91a2ec8e7fa0

demandimport: stop overriding __getattribute__() Proxy __dict__ and __doc__ explicitly instead. I'm not sure which is less evil, but this seems slightly simpler than hooking all attribute accesses.
author Yuya Nishihara <yuya@tcha.org>
date Fri, 28 Apr 2017 00:01:22 +0900
parents 252d2260c74e
children 0ed730f3301c
files hgdemandimport/demandimportpy2.py tests/test-demandimport.py tests/test-demandimport.py.out
diffstat 3 files changed, 27 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/hgdemandimport/demandimportpy2.py	Fri Apr 28 23:46:16 2017 +0900
+++ b/hgdemandimport/demandimportpy2.py	Fri Apr 28 00:01:22 2017 +0900
@@ -153,9 +153,7 @@
     def __call__(self, *args, **kwargs):
         raise TypeError("%s object is not callable" % repr(self))
 
-    def __getattribute__(self, attr):
-        if attr in ('_data', '_extend', '_load', '_module', '_addref'):
-            return object.__getattribute__(self, attr)
+    def __getattr__(self, attr):
         self._load()
         return getattr(self._module, attr)
 
@@ -163,6 +161,16 @@
         self._load()
         setattr(self._module, attr, val)
 
+    @property
+    def __dict__(self):
+        self._load()
+        return self._module.__dict__
+
+    @property
+    def __doc__(self):
+        self._load()
+        return self._module.__doc__
+
 _pypy = '__pypy__' in sys.builtin_module_names
 
 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
--- a/tests/test-demandimport.py	Fri Apr 28 23:46:16 2017 +0900
+++ b/tests/test-demandimport.py	Fri Apr 28 00:01:22 2017 +0900
@@ -69,6 +69,17 @@
 print("re.stderr =", f(re.stderr))
 print("re =", f(re))
 
+# Test access to special attributes through demandmod proxy
+from mercurial import pvec as pvecproxy
+print("pvecproxy =", f(pvecproxy))
+print("pvecproxy.__doc__ = %r"
+      % (' '.join(pvecproxy.__doc__.split()[:3]) + ' ...'))
+print("pvecproxy.__name__ = %r" % pvecproxy.__name__)
+# __name__ must be accessible via __dict__ so the relative imports can be
+# resolved
+print("pvecproxy.__dict__['__name__'] = %r" % pvecproxy.__dict__['__name__'])
+print("pvecproxy =", f(pvecproxy))
+
 import contextlib
 print("contextlib =", f(contextlib))
 try:
--- a/tests/test-demandimport.py.out	Fri Apr 28 23:46:16 2017 +0900
+++ b/tests/test-demandimport.py.out	Fri Apr 28 00:01:22 2017 +0900
@@ -18,6 +18,11 @@
 re = <unloaded module 'sys'>
 re.stderr = <open file '<whatever>', mode 'w' at 0x?>
 re = <proxied module 'sys'>
+pvecproxy = <unloaded module 'pvec'>
+pvecproxy.__doc__ = 'A "pvec" is ...'
+pvecproxy.__name__ = 'mercurial.pvec'
+pvecproxy.__dict__['__name__'] = 'mercurial.pvec'
+pvecproxy = <proxied module 'pvec'>
 contextlib = <unloaded module 'contextlib'>
 contextlib.unknownattr = ImportError: cannot import name unknownattr
 __import__('contextlib', ..., ['unknownattr']) = <module 'contextlib' from '?'>