policy.py
109 lines
| 3.6 KiB
| text/x-python
|
PythonLexer
/ mercurial / policy.py
|
r29266 | # policy.py - module policy logic for Mercurial. | ||
# | ||||
# Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com> | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | ||||
import os | ||||
import sys | ||||
# Rules for how modules can be loaded. Values are: | ||||
# | ||||
# c - require C extensions | ||||
# allow - allow pure Python implementation when C loading fails | ||||
|
r29490 | # cffi - required cffi versions (implemented within pure module) | ||
# cffi-allow - allow pure Python implementation if cffi version is missing | ||||
|
r29266 | # py - only load pure Python modules | ||
# | ||||
|
r32251 | # By default, fall back to the pure modules so the in-place build can | ||
# run without recompiling the C extensions. This will be overridden by | ||||
# __modulepolicy__ generated by setup.py. | ||||
policy = b'allow' | ||||
|
r32366 | _packageprefs = { | ||
# policy: (versioned package, pure package) | ||||
b'c': (r'cext', None), | ||||
b'allow': (r'cext', r'pure'), | ||||
|
r32512 | b'cffi': (r'cffi', None), | ||
b'cffi-allow': (r'cffi', r'pure'), | ||||
|
r32366 | b'py': (None, r'pure'), | ||
} | ||||
|
r29490 | |||
|
r29266 | try: | ||
from . import __modulepolicy__ | ||||
policy = __modulepolicy__.modulepolicy | ||||
except ImportError: | ||||
pass | ||||
# PyPy doesn't load C extensions. | ||||
# | ||||
# The canonical way to do this is to test platform.python_implementation(). | ||||
# But we don't import platform and don't bloat for it here. | ||||
|
r32205 | if r'__pypy__' in sys.builtin_module_names: | ||
policy = b'cffi' | ||||
|
r29266 | |||
# Environment variable can always force settings. | ||||
|
r31361 | if sys.version_info[0] >= 3: | ||
|
r32205 | if r'HGMODULEPOLICY' in os.environ: | ||
policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8') | ||||
|
r31361 | else: | ||
|
r32205 | policy = os.environ.get(r'HGMODULEPOLICY', policy) | ||
|
r32366 | |||
def _importfrom(pkgname, modname): | ||||
# from .<pkgname> import <modname> (where . is looked through this module) | ||||
fakelocals = {} | ||||
pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1) | ||||
try: | ||||
fakelocals[modname] = mod = getattr(pkg, modname) | ||||
except AttributeError: | ||||
raise ImportError(r'cannot import name %s' % modname) | ||||
# force import; fakelocals[modname] may be replaced with the real module | ||||
getattr(mod, r'__doc__', None) | ||||
return fakelocals[modname] | ||||
|
r32428 | # keep in sync with "version" in C modules | ||
_cextversions = { | ||||
|
r32511 | (r'cext', r'base85'): 1, | ||
|
r36693 | (r'cext', r'bdiff'): 3, | ||
|
r32511 | (r'cext', r'mpatch'): 1, | ||
|
r36798 | (r'cext', r'osutil'): 4, | ||
|
r39485 | (r'cext', r'parsers'): 10, | ||
|
r32428 | } | ||
|
r33755 | # map import request to other package or module | ||
_modredirects = { | ||||
|
r33756 | (r'cext', r'charencode'): (r'cext', r'parsers'), | ||
|
r33755 | (r'cffi', r'base85'): (r'pure', r'base85'), | ||
|
r33756 | (r'cffi', r'charencode'): (r'pure', r'charencode'), | ||
|
r33755 | (r'cffi', r'parsers'): (r'pure', r'parsers'), | ||
} | ||||
|
r32366 | def _checkmod(pkgname, modname, mod): | ||
|
r32511 | expected = _cextversions.get((pkgname, modname)) | ||
|
r32366 | actual = getattr(mod, r'version', None) | ||
if actual != expected: | ||||
raise ImportError(r'cannot import module %s.%s ' | ||||
r'(expected version: %d, actual: %r)' | ||||
% (pkgname, modname, expected, actual)) | ||||
def importmod(modname): | ||||
"""Import module according to policy and check API version""" | ||||
try: | ||||
verpkg, purepkg = _packageprefs[policy] | ||||
except KeyError: | ||||
raise ImportError(r'invalid HGMODULEPOLICY %r' % policy) | ||||
assert verpkg or purepkg | ||||
if verpkg: | ||||
|
r33755 | pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname)) | ||
|
r32366 | try: | ||
|
r33755 | mod = _importfrom(pn, mn) | ||
if pn == verpkg: | ||||
_checkmod(pn, mn, mod) | ||||
|
r32366 | return mod | ||
except ImportError: | ||||
if not purepkg: | ||||
raise | ||||
|
r33755 | pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname)) | ||
return _importfrom(pn, mn) | ||||