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