##// END OF EJS Templates
py3: unblock C extensions on Python 3...
Yuya Nishihara -
r36645:418f9ea2 default
parent child Browse files
Show More
@@ -1,116 +1,111 b''
1 # policy.py - module policy logic for Mercurial.
1 # policy.py - module policy 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 os
10 import os
11 import sys
11 import sys
12
12
13 # Rules for how modules can be loaded. Values are:
13 # Rules for how modules can be loaded. Values are:
14 #
14 #
15 # c - require C extensions
15 # c - require C extensions
16 # allow - allow pure Python implementation when C loading fails
16 # allow - allow pure Python implementation when C loading fails
17 # cffi - required cffi versions (implemented within pure module)
17 # cffi - required cffi versions (implemented within pure module)
18 # cffi-allow - allow pure Python implementation if cffi version is missing
18 # cffi-allow - allow pure Python implementation if cffi version is missing
19 # py - only load pure Python modules
19 # py - only load pure Python modules
20 #
20 #
21 # By default, fall back to the pure modules so the in-place build can
21 # By default, fall back to the pure modules so the in-place build can
22 # run without recompiling the C extensions. This will be overridden by
22 # run without recompiling the C extensions. This will be overridden by
23 # __modulepolicy__ generated by setup.py.
23 # __modulepolicy__ generated by setup.py.
24 policy = b'allow'
24 policy = b'allow'
25 _packageprefs = {
25 _packageprefs = {
26 # policy: (versioned package, pure package)
26 # policy: (versioned package, pure package)
27 b'c': (r'cext', None),
27 b'c': (r'cext', None),
28 b'allow': (r'cext', r'pure'),
28 b'allow': (r'cext', r'pure'),
29 b'cffi': (r'cffi', None),
29 b'cffi': (r'cffi', None),
30 b'cffi-allow': (r'cffi', r'pure'),
30 b'cffi-allow': (r'cffi', r'pure'),
31 b'py': (None, r'pure'),
31 b'py': (None, r'pure'),
32 }
32 }
33
33
34 try:
34 try:
35 from . import __modulepolicy__
35 from . import __modulepolicy__
36 policy = __modulepolicy__.modulepolicy
36 policy = __modulepolicy__.modulepolicy
37 except ImportError:
37 except ImportError:
38 pass
38 pass
39
39
40 # PyPy doesn't load C extensions.
40 # PyPy doesn't load C extensions.
41 #
41 #
42 # The canonical way to do this is to test platform.python_implementation().
42 # The canonical way to do this is to test platform.python_implementation().
43 # But we don't import platform and don't bloat for it here.
43 # But we don't import platform and don't bloat for it here.
44 if r'__pypy__' in sys.builtin_module_names:
44 if r'__pypy__' in sys.builtin_module_names:
45 policy = b'cffi'
45 policy = b'cffi'
46
46
47 # Our C extensions aren't yet compatible with Python 3. So use pure Python
48 # on Python 3 for now.
49 if sys.version_info[0] >= 3:
50 policy = b'py'
51
52 # Environment variable can always force settings.
47 # Environment variable can always force settings.
53 if sys.version_info[0] >= 3:
48 if sys.version_info[0] >= 3:
54 if r'HGMODULEPOLICY' in os.environ:
49 if r'HGMODULEPOLICY' in os.environ:
55 policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8')
50 policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8')
56 else:
51 else:
57 policy = os.environ.get(r'HGMODULEPOLICY', policy)
52 policy = os.environ.get(r'HGMODULEPOLICY', policy)
58
53
59 def _importfrom(pkgname, modname):
54 def _importfrom(pkgname, modname):
60 # from .<pkgname> import <modname> (where . is looked through this module)
55 # from .<pkgname> import <modname> (where . is looked through this module)
61 fakelocals = {}
56 fakelocals = {}
62 pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
57 pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
63 try:
58 try:
64 fakelocals[modname] = mod = getattr(pkg, modname)
59 fakelocals[modname] = mod = getattr(pkg, modname)
65 except AttributeError:
60 except AttributeError:
66 raise ImportError(r'cannot import name %s' % modname)
61 raise ImportError(r'cannot import name %s' % modname)
67 # force import; fakelocals[modname] may be replaced with the real module
62 # force import; fakelocals[modname] may be replaced with the real module
68 getattr(mod, r'__doc__', None)
63 getattr(mod, r'__doc__', None)
69 return fakelocals[modname]
64 return fakelocals[modname]
70
65
71 # keep in sync with "version" in C modules
66 # keep in sync with "version" in C modules
72 _cextversions = {
67 _cextversions = {
73 (r'cext', r'base85'): 1,
68 (r'cext', r'base85'): 1,
74 (r'cext', r'bdiff'): 2,
69 (r'cext', r'bdiff'): 2,
75 (r'cext', r'diffhelpers'): 1,
70 (r'cext', r'diffhelpers'): 1,
76 (r'cext', r'mpatch'): 1,
71 (r'cext', r'mpatch'): 1,
77 (r'cext', r'osutil'): 3,
72 (r'cext', r'osutil'): 3,
78 (r'cext', r'parsers'): 4,
73 (r'cext', r'parsers'): 4,
79 }
74 }
80
75
81 # map import request to other package or module
76 # map import request to other package or module
82 _modredirects = {
77 _modredirects = {
83 (r'cext', r'charencode'): (r'cext', r'parsers'),
78 (r'cext', r'charencode'): (r'cext', r'parsers'),
84 (r'cffi', r'base85'): (r'pure', r'base85'),
79 (r'cffi', r'base85'): (r'pure', r'base85'),
85 (r'cffi', r'charencode'): (r'pure', r'charencode'),
80 (r'cffi', r'charencode'): (r'pure', r'charencode'),
86 (r'cffi', r'diffhelpers'): (r'pure', r'diffhelpers'),
81 (r'cffi', r'diffhelpers'): (r'pure', r'diffhelpers'),
87 (r'cffi', r'parsers'): (r'pure', r'parsers'),
82 (r'cffi', r'parsers'): (r'pure', r'parsers'),
88 }
83 }
89
84
90 def _checkmod(pkgname, modname, mod):
85 def _checkmod(pkgname, modname, mod):
91 expected = _cextversions.get((pkgname, modname))
86 expected = _cextversions.get((pkgname, modname))
92 actual = getattr(mod, r'version', None)
87 actual = getattr(mod, r'version', None)
93 if actual != expected:
88 if actual != expected:
94 raise ImportError(r'cannot import module %s.%s '
89 raise ImportError(r'cannot import module %s.%s '
95 r'(expected version: %d, actual: %r)'
90 r'(expected version: %d, actual: %r)'
96 % (pkgname, modname, expected, actual))
91 % (pkgname, modname, expected, actual))
97
92
98 def importmod(modname):
93 def importmod(modname):
99 """Import module according to policy and check API version"""
94 """Import module according to policy and check API version"""
100 try:
95 try:
101 verpkg, purepkg = _packageprefs[policy]
96 verpkg, purepkg = _packageprefs[policy]
102 except KeyError:
97 except KeyError:
103 raise ImportError(r'invalid HGMODULEPOLICY %r' % policy)
98 raise ImportError(r'invalid HGMODULEPOLICY %r' % policy)
104 assert verpkg or purepkg
99 assert verpkg or purepkg
105 if verpkg:
100 if verpkg:
106 pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
101 pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
107 try:
102 try:
108 mod = _importfrom(pn, mn)
103 mod = _importfrom(pn, mn)
109 if pn == verpkg:
104 if pn == verpkg:
110 _checkmod(pn, mn, mod)
105 _checkmod(pn, mn, mod)
111 return mod
106 return mod
112 except ImportError:
107 except ImportError:
113 if not purepkg:
108 if not purepkg:
114 raise
109 raise
115 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
110 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
116 return _importfrom(pn, mn)
111 return _importfrom(pn, mn)
General Comments 0
You need to be logged in to leave comments. Login now