Mercurial > hg
comparison mercurial/policy.py @ 42451:810f66b468cd
rust: module policy with importrust
We introduce two rust+c module policies and a new
`policy.importrust()` that makes use of them.
This simple approach provides runtime switching of
implementations, which is crucial for the performance
measurements such as those Octobus does with ASV.
It can also be useful for bug analysis.
It also has the advantage of making conditionals in
Rust callers more uniform, in particular
abstracting over specifics like `demandimport`
At this point, the build stays unchanged, with the rust-cpython based
`rustext` module being built if HGWITHRUSTEXT=cpython.
More transparency for the callers, i.e., just using
`policy.importmod` would be a much longer term and riskier
effort for the following reasons:
1. It would require to define common module boundaries
for the three or four cases (pure, c, rust+ext, cffi) and that
is premature with the Rust extension currently under heavy
development in areas that are outside the scope of the C extensions.
2. It would imply internal API changes that are not currently wished,
as the case of ancestors demonstrates.
3. The lack of data or property-like attributes (tp_member
and tp_getset) in current `rust-cpython` makes it impossible to
achieve direct transparent replacement of pure Python classes by
Rust extension code, meaning that the caller sometimes has to be able
to make adjustments or provide additional wrapping.
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Wed, 29 May 2019 13:27:56 +0200 |
parents | d8e55c0c642c |
children | 57875cf423c9 |
comparison
equal
deleted
inserted
replaced
42450:9d31581cc44e | 42451:810f66b468cd |
---|---|
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 # rust+c - require Rust and C extensions | |
17 # rust+c-allow - allow Rust and C extensions with fallback to pure Python | |
18 # for each | |
16 # allow - allow pure Python implementation when C loading fails | 19 # allow - allow pure Python implementation when C loading fails |
17 # cffi - required cffi versions (implemented within pure module) | 20 # cffi - required cffi versions (implemented within pure module) |
18 # cffi-allow - allow pure Python implementation if cffi version is missing | 21 # cffi-allow - allow pure Python implementation if cffi version is missing |
19 # py - only load pure Python modules | 22 # py - only load pure Python modules |
20 # | 23 # |
27 b'c': (r'cext', None), | 30 b'c': (r'cext', None), |
28 b'allow': (r'cext', r'pure'), | 31 b'allow': (r'cext', r'pure'), |
29 b'cffi': (r'cffi', None), | 32 b'cffi': (r'cffi', None), |
30 b'cffi-allow': (r'cffi', r'pure'), | 33 b'cffi-allow': (r'cffi', r'pure'), |
31 b'py': (None, r'pure'), | 34 b'py': (None, r'pure'), |
35 # For now, rust policies impact importrust only | |
36 b'rust+c': (r'cext', None), | |
37 b'rust+c-allow': (r'cext', r'pure'), | |
32 } | 38 } |
33 | 39 |
34 try: | 40 try: |
35 from . import __modulepolicy__ | 41 from . import __modulepolicy__ |
36 policy = __modulepolicy__.modulepolicy | 42 policy = __modulepolicy__.modulepolicy |
105 except ImportError: | 111 except ImportError: |
106 if not purepkg: | 112 if not purepkg: |
107 raise | 113 raise |
108 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname)) | 114 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname)) |
109 return _importfrom(pn, mn) | 115 return _importfrom(pn, mn) |
116 | |
117 def _isrustpermissive(): | |
118 """Assuming the policy is a Rust one, tell if it's permissive.""" | |
119 return policy.endswith(b'-allow') | |
120 | |
121 def importrust(modname, member=None, default=None): | |
122 """Import Rust module according to policy and availability. | |
123 | |
124 If policy isn't a Rust one, this returns `default`. | |
125 | |
126 If either the module or its member is not available, this returns `default` | |
127 if policy is permissive and raises `ImportError` if not. | |
128 """ | |
129 if not policy.startswith(b'rust'): | |
130 return default | |
131 | |
132 try: | |
133 mod = _importfrom(r'rustext', modname) | |
134 except ImportError: | |
135 if _isrustpermissive(): | |
136 return default | |
137 raise | |
138 if member is None: | |
139 return mod | |
140 | |
141 try: | |
142 return getattr(mod, member) | |
143 except AttributeError: | |
144 if _isrustpermissive(): | |
145 return default | |
146 raise ImportError(r"Cannot import name %s" % member) |