##// END OF EJS Templates
policy: remove Python 2.7 compatibility code...
Gregory Szorc -
r49793:f98da134 default
parent child Browse files
Show More
@@ -1,156 +1,153 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
8
9 import os
9 import os
10 import sys
10 import sys
11
11
12 from .pycompat import getattr
12 from .pycompat import getattr
13
13
14 # Rules for how modules can be loaded. Values are:
14 # Rules for how modules can be loaded. Values are:
15 #
15 #
16 # c - require C extensions
16 # c - require C extensions
17 # rust+c - require Rust and C extensions
17 # rust+c - require Rust and C extensions
18 # rust+c-allow - allow Rust and C extensions with fallback to pure Python
18 # rust+c-allow - allow Rust and C extensions with fallback to pure Python
19 # for each
19 # for each
20 # allow - allow pure Python implementation when C loading fails
20 # allow - allow pure Python implementation when C loading fails
21 # cffi - required cffi versions (implemented within pure module)
21 # cffi - required cffi versions (implemented within pure module)
22 # cffi-allow - allow pure Python implementation if cffi version is missing
22 # cffi-allow - allow pure Python implementation if cffi version is missing
23 # py - only load pure Python modules
23 # py - only load pure Python modules
24 #
24 #
25 # By default, fall back to the pure modules so the in-place build can
25 # By default, fall back to the pure modules so the in-place build can
26 # run without recompiling the C extensions. This will be overridden by
26 # run without recompiling the C extensions. This will be overridden by
27 # __modulepolicy__ generated by setup.py.
27 # __modulepolicy__ generated by setup.py.
28 policy = b'allow'
28 policy = b'allow'
29 _packageprefs = {
29 _packageprefs = {
30 # policy: (versioned package, pure package)
30 # policy: (versioned package, pure package)
31 b'c': ('cext', None),
31 b'c': ('cext', None),
32 b'allow': ('cext', 'pure'),
32 b'allow': ('cext', 'pure'),
33 b'cffi': ('cffi', None),
33 b'cffi': ('cffi', None),
34 b'cffi-allow': ('cffi', 'pure'),
34 b'cffi-allow': ('cffi', 'pure'),
35 b'py': (None, 'pure'),
35 b'py': (None, 'pure'),
36 # For now, rust policies impact importrust only
36 # For now, rust policies impact importrust only
37 b'rust+c': ('cext', None),
37 b'rust+c': ('cext', None),
38 b'rust+c-allow': ('cext', 'pure'),
38 b'rust+c-allow': ('cext', 'pure'),
39 }
39 }
40
40
41 try:
41 try:
42 from . import __modulepolicy__
42 from . import __modulepolicy__
43
43
44 policy = __modulepolicy__.modulepolicy
44 policy = __modulepolicy__.modulepolicy
45 except ImportError:
45 except ImportError:
46 pass
46 pass
47
47
48 # PyPy doesn't load C extensions.
48 # PyPy doesn't load C extensions.
49 #
49 #
50 # The canonical way to do this is to test platform.python_implementation().
50 # The canonical way to do this is to test platform.python_implementation().
51 # But we don't import platform and don't bloat for it here.
51 # But we don't import platform and don't bloat for it here.
52 if '__pypy__' in sys.builtin_module_names:
52 if '__pypy__' in sys.builtin_module_names:
53 policy = b'cffi'
53 policy = b'cffi'
54
54
55 # Environment variable can always force settings.
55 # Environment variable can always force settings.
56 if sys.version_info[0] >= 3:
56 if 'HGMODULEPOLICY' in os.environ:
57 if 'HGMODULEPOLICY' in os.environ:
57 policy = os.environ['HGMODULEPOLICY'].encode('utf-8')
58 policy = os.environ['HGMODULEPOLICY'].encode('utf-8')
59 else:
60 policy = os.environ.get('HGMODULEPOLICY', policy)
61
58
62
59
63 def _importfrom(pkgname, modname):
60 def _importfrom(pkgname, modname):
64 # from .<pkgname> import <modname> (where . is looked through this module)
61 # from .<pkgname> import <modname> (where . is looked through this module)
65 fakelocals = {}
62 fakelocals = {}
66 pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
63 pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
67 try:
64 try:
68 fakelocals[modname] = mod = getattr(pkg, modname)
65 fakelocals[modname] = mod = getattr(pkg, modname)
69 except AttributeError:
66 except AttributeError:
70 raise ImportError('cannot import name %s' % modname)
67 raise ImportError('cannot import name %s' % modname)
71 # force import; fakelocals[modname] may be replaced with the real module
68 # force import; fakelocals[modname] may be replaced with the real module
72 getattr(mod, '__doc__', None)
69 getattr(mod, '__doc__', None)
73 return fakelocals[modname]
70 return fakelocals[modname]
74
71
75
72
76 # keep in sync with "version" in C modules
73 # keep in sync with "version" in C modules
77 _cextversions = {
74 _cextversions = {
78 ('cext', 'base85'): 1,
75 ('cext', 'base85'): 1,
79 ('cext', 'bdiff'): 3,
76 ('cext', 'bdiff'): 3,
80 ('cext', 'mpatch'): 1,
77 ('cext', 'mpatch'): 1,
81 ('cext', 'osutil'): 4,
78 ('cext', 'osutil'): 4,
82 ('cext', 'parsers'): 20,
79 ('cext', 'parsers'): 20,
83 }
80 }
84
81
85 # map import request to other package or module
82 # map import request to other package or module
86 _modredirects = {
83 _modredirects = {
87 ('cext', 'charencode'): ('cext', 'parsers'),
84 ('cext', 'charencode'): ('cext', 'parsers'),
88 ('cffi', 'base85'): ('pure', 'base85'),
85 ('cffi', 'base85'): ('pure', 'base85'),
89 ('cffi', 'charencode'): ('pure', 'charencode'),
86 ('cffi', 'charencode'): ('pure', 'charencode'),
90 ('cffi', 'parsers'): ('pure', 'parsers'),
87 ('cffi', 'parsers'): ('pure', 'parsers'),
91 }
88 }
92
89
93
90
94 def _checkmod(pkgname, modname, mod):
91 def _checkmod(pkgname, modname, mod):
95 expected = _cextversions.get((pkgname, modname))
92 expected = _cextversions.get((pkgname, modname))
96 actual = getattr(mod, 'version', None)
93 actual = getattr(mod, 'version', None)
97 if actual != expected:
94 if actual != expected:
98 raise ImportError(
95 raise ImportError(
99 'cannot import module %s.%s '
96 'cannot import module %s.%s '
100 '(expected version: %d, actual: %r)'
97 '(expected version: %d, actual: %r)'
101 % (pkgname, modname, expected, actual)
98 % (pkgname, modname, expected, actual)
102 )
99 )
103
100
104
101
105 def importmod(modname):
102 def importmod(modname):
106 """Import module according to policy and check API version"""
103 """Import module according to policy and check API version"""
107 try:
104 try:
108 verpkg, purepkg = _packageprefs[policy]
105 verpkg, purepkg = _packageprefs[policy]
109 except KeyError:
106 except KeyError:
110 raise ImportError('invalid HGMODULEPOLICY %r' % policy)
107 raise ImportError('invalid HGMODULEPOLICY %r' % policy)
111 assert verpkg or purepkg
108 assert verpkg or purepkg
112 if verpkg:
109 if verpkg:
113 pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
110 pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
114 try:
111 try:
115 mod = _importfrom(pn, mn)
112 mod = _importfrom(pn, mn)
116 if pn == verpkg:
113 if pn == verpkg:
117 _checkmod(pn, mn, mod)
114 _checkmod(pn, mn, mod)
118 return mod
115 return mod
119 except ImportError:
116 except ImportError:
120 if not purepkg:
117 if not purepkg:
121 raise
118 raise
122 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
119 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
123 return _importfrom(pn, mn)
120 return _importfrom(pn, mn)
124
121
125
122
126 def _isrustpermissive():
123 def _isrustpermissive():
127 """Assuming the policy is a Rust one, tell if it's permissive."""
124 """Assuming the policy is a Rust one, tell if it's permissive."""
128 return policy.endswith(b'-allow')
125 return policy.endswith(b'-allow')
129
126
130
127
131 def importrust(modname, member=None, default=None):
128 def importrust(modname, member=None, default=None):
132 """Import Rust module according to policy and availability.
129 """Import Rust module according to policy and availability.
133
130
134 If policy isn't a Rust one, this returns `default`.
131 If policy isn't a Rust one, this returns `default`.
135
132
136 If either the module or its member is not available, this returns `default`
133 If either the module or its member is not available, this returns `default`
137 if policy is permissive and raises `ImportError` if not.
134 if policy is permissive and raises `ImportError` if not.
138 """
135 """
139 if not policy.startswith(b'rust'):
136 if not policy.startswith(b'rust'):
140 return default
137 return default
141
138
142 try:
139 try:
143 mod = _importfrom('rustext', modname)
140 mod = _importfrom('rustext', modname)
144 except ImportError:
141 except ImportError:
145 if _isrustpermissive():
142 if _isrustpermissive():
146 return default
143 return default
147 raise
144 raise
148 if member is None:
145 if member is None:
149 return mod
146 return mod
150
147
151 try:
148 try:
152 return getattr(mod, member)
149 return getattr(mod, member)
153 except AttributeError:
150 except AttributeError:
154 if _isrustpermissive():
151 if _isrustpermissive():
155 return default
152 return default
156 raise ImportError("Cannot import name %s" % member)
153 raise ImportError("Cannot import name %s" % member)
General Comments 0
You need to be logged in to leave comments. Login now