[PATCH 2 of 3 v2] demandimport: suppport rejecting modules based on requested properties

timeless timeless at fmr.im
Wed Sep 21 14:09:41 EDT 2016


# HG changeset patch
# User timeless <timeless at mozdev.org>
# Date 1474429655 0
#      Wed Sep 21 03:47:35 2016 +0000
# Node ID 20111b4d031e63596b93e162af9b8ca3ff1c98af
# Parent  32a4cb17f935c570817249721401e0d62033987d
# Available At https://bitbucket.org/timeless/mercurial-crew
#              hg pull https://bitbucket.org/timeless/mercurial-crew -r 20111b4d031e
demandimport: suppport rejecting modules based on requested properties

Some code uses:
try:
 from Foo import Bar
except ImportError:
 from Foo import Bar2

demandimport exposes Bar as an unloaded module without checking to
see whether or not it really exists this enables it to improve loading
speed.

Unfortunately, any code that expects to get an ImportError won't get
one.

This code enables callers to tell demandimport about the shape of some
libraries to enable it to replicate the exception that callers expect.

without demandimport:
>>> from contextlib import _GeneratorContextManager
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name _GeneratorContextManager

with demandimport without reject:
>>> from __future__ import absolute_import
>>> from mercurial import demandimport
>>> demandimport.enable()
>>> from contextlib import _GeneratorContextManager
>>> _GeneratorContextManager
<unloaded module '_GeneratorContextManager'>

with demandimport and reject:
>>> from __future__ import absolute_import
>>> from mercurial import demandimport
>>> demandimport.enable()
>>> demandimport.reject("contextlib", "_GeneratorContextManager", ImportError, "cannot import name _GeneratorContextManager")
>>> from contextlib import _GeneratorContextManager
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "mercurial/demandimport.py", line 260, in _demandimport
    processfromlist(mod, name, fromlist)
  File "mercurial/demandimport.py", line 235, in processfromlist
    raise cls(msg)
ImportError: cannot import name _GeneratorContextManager

diff -r 32a4cb17f935 -r 20111b4d031e mercurial/demandimport.py
--- a/mercurial/demandimport.py	Wed Sep 21 03:40:51 2016 +0000
+++ b/mercurial/demandimport.py	Wed Sep 21 03:47:35 2016 +0000
@@ -222,9 +222,18 @@
 
         def processfromlist(mod, name, fromlist):
             # call processfromitem for each item in fromlist
-            if True:
+            # if a module property is registered for rejection,
+            # raise the specified exception
+            if not name in rejects:
                 for x in fromlist:
                     processfromitem(mod, x)
+            else:
+                reject = rejects[name]
+                for x in fromlist:
+                    if x in reject:
+                        cls, msg = reject[x]
+                        raise cls(msg)
+                    processfromitem(mod, x)
 
         if level >= 0:
             if name:
@@ -290,6 +299,16 @@
     'distutils.msvc9compiler',
     ]
 
+rejects = {}
+
+def reject(mod, prop, cls, msg):
+    """inform demandimport that a module does not have a property
+
+    arguments are the class and message to raise when code tries to
+    import it."""
+    if not mod in rejects:
+        rejects[mod] = {}
+    rejects[mod][prop] = [cls, msg]
 def isenabled():
     return builtins.__import__ == _demandimport
 
diff -r 32a4cb17f935 -r 20111b4d031e tests/test-demandimport.py
--- a/tests/test-demandimport.py	Wed Sep 21 03:40:51 2016 +0000
+++ b/tests/test-demandimport.py	Wed Sep 21 03:47:35 2016 +0000
@@ -63,6 +63,14 @@
 print("re.stderr =", f(re.stderr))
 print("re =", f(re))
 
+demandimport.reject('chunk', 'Chunk', ImportError, 'boo')
+try:
+    from chunk import Chunk
+    print('reject should prevent chunk from loading for Chunk')
+    Chunk.getname
+except ImportError:
+    pass
+
 demandimport.disable()
 os.environ['HGDEMANDIMPORT'] = 'disable'
 # this enable call should not actually enable demandimport!


More information about the Mercurial-devel mailing list