##// END OF EJS Templates
mercurial: use pure Python module policy on Python 3...
Gregory Szorc -
r28513:859af6e7 default
parent child Browse files
Show More
@@ -1,147 +1,152 b''
1 1 # __init__.py - Startup and module loading logic for Mercurial.
2 2 #
3 3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import imp
11 11 import os
12 12 import sys
13 13 import zipimport
14 14
15 15 __all__ = []
16 16
17 17 # Rules for how modules can be loaded. Values are:
18 18 #
19 19 # c - require C extensions
20 20 # allow - allow pure Python implementation when C loading fails
21 21 # py - only load pure Python modules
22 22 #
23 23 # By default, require the C extensions for performance reasons.
24 24 modulepolicy = 'c'
25 25 try:
26 26 from . import __modulepolicy__
27 27 modulepolicy = __modulepolicy__.modulepolicy
28 28 except ImportError:
29 29 pass
30 30
31 31 # PyPy doesn't load C extensions.
32 32 #
33 33 # The canonical way to do this is to test platform.python_implementation().
34 34 # But we don't import platform and don't bloat for it here.
35 35 if '__pypy__' in sys.builtin_module_names:
36 36 modulepolicy = 'py'
37 37
38 # Our C extensions aren't yet compatible with Python 3. So use pure Python
39 # on Python 3 for now.
40 if sys.version_info[0] >= 3:
41 modulepolicy = 'py'
42
38 43 # Environment variable can always force settings.
39 44 modulepolicy = os.environ.get('HGMODULEPOLICY', modulepolicy)
40 45
41 46 # Modules that have both Python and C implementations. See also the
42 47 # set of .py files under mercurial/pure/.
43 48 _dualmodules = set([
44 49 'mercurial.base85',
45 50 'mercurial.bdiff',
46 51 'mercurial.diffhelpers',
47 52 'mercurial.mpatch',
48 53 'mercurial.osutil',
49 54 'mercurial.parsers',
50 55 ])
51 56
52 57 class hgimporter(object):
53 58 """Object that conforms to import hook interface defined in PEP-302."""
54 59 def find_module(self, name, path=None):
55 60 # We only care about modules that have both C and pure implementations.
56 61 if name in _dualmodules:
57 62 return self
58 63 return None
59 64
60 65 def load_module(self, name):
61 66 mod = sys.modules.get(name, None)
62 67 if mod:
63 68 return mod
64 69
65 70 mercurial = sys.modules['mercurial']
66 71
67 72 # The zip importer behaves sufficiently differently from the default
68 73 # importer to warrant its own code path.
69 74 loader = getattr(mercurial, '__loader__', None)
70 75 if isinstance(loader, zipimport.zipimporter):
71 76 def ziploader(*paths):
72 77 """Obtain a zipimporter for a directory under the main zip."""
73 78 path = os.path.join(loader.archive, *paths)
74 79 zl = sys.path_importer_cache.get(path)
75 80 if not zl:
76 81 zl = zipimport.zipimporter(path)
77 82 return zl
78 83
79 84 try:
80 85 if modulepolicy == 'py':
81 86 raise ImportError()
82 87
83 88 zl = ziploader('mercurial')
84 89 mod = zl.load_module(name)
85 90 # Unlike imp, ziploader doesn't expose module metadata that
86 91 # indicates the type of module. So just assume what we found
87 92 # is OK (even though it could be a pure Python module).
88 93 except ImportError:
89 94 if modulepolicy == 'c':
90 95 raise
91 96 zl = ziploader('mercurial', 'pure')
92 97 mod = zl.load_module(name)
93 98
94 99 sys.modules[name] = mod
95 100 return mod
96 101
97 102 # Unlike the default importer which searches special locations and
98 103 # sys.path, we only look in the directory where "mercurial" was
99 104 # imported from.
100 105
101 106 # imp.find_module doesn't support submodules (modules with ".").
102 107 # Instead you have to pass the parent package's __path__ attribute
103 108 # as the path argument.
104 109 stem = name.split('.')[-1]
105 110
106 111 try:
107 112 if modulepolicy == 'py':
108 113 raise ImportError()
109 114
110 115 modinfo = imp.find_module(stem, mercurial.__path__)
111 116
112 117 # The Mercurial installer used to copy files from
113 118 # mercurial/pure/*.py to mercurial/*.py. Therefore, it's possible
114 119 # for some installations to have .py files under mercurial/*.
115 120 # Loading Python modules when we expected C versions could result
116 121 # in a) poor performance b) loading a version from a previous
117 122 # Mercurial version, potentially leading to incompatibility. Either
118 123 # scenario is bad. So we verify that modules loaded from
119 124 # mercurial/* are C extensions. If the current policy allows the
120 125 # loading of .py modules, the module will be re-imported from
121 126 # mercurial/pure/* below.
122 127 if modinfo[2][2] != imp.C_EXTENSION:
123 128 raise ImportError('.py version of %s found where C '
124 129 'version should exist' % name)
125 130
126 131 except ImportError:
127 132 if modulepolicy == 'c':
128 133 raise
129 134
130 135 # Could not load the C extension and pure Python is allowed. So
131 136 # try to load them.
132 137 from . import pure
133 138 modinfo = imp.find_module(stem, pure.__path__)
134 139 if not modinfo:
135 140 raise ImportError('could not find mercurial module %s' %
136 141 name)
137 142
138 143 mod = imp.load_module(name, *modinfo)
139 144 sys.modules[name] = mod
140 145 return mod
141 146
142 147 # We automagically register our custom importer as a side-effect of loading.
143 148 # This is necessary to ensure that any entry points are able to import
144 149 # mercurial.* modules without having to perform this registration themselves.
145 150 if not any(isinstance(x, hgimporter) for x in sys.meta_path):
146 151 # meta_path is used before any implicit finders and before sys.path.
147 152 sys.meta_path.insert(0, hgimporter())
General Comments 0
You need to be logged in to leave comments. Login now