sapling/edenscm/mercurial/policy.py
Jun Wu c12e300bb8 codemod: move Python packages to edenscm
Summary:
Move top-level Python packages `mercurial`, `hgext` and `hgdemandimport` to
a new top-level package `edenscm`. This allows the Python packages provided by
the upstream Mercurial to be installed side-by-side.

To maintain compatibility, `edenscm/` gets added to `sys.path` in
`mercurial/__init__.py`.

Reviewed By: phillco, ikostia

Differential Revision: D13853115

fbshipit-source-id: b296b0673dc54c61ef6a591ebc687057ff53b22e
2019-01-28 18:35:41 -08:00

124 lines
3.8 KiB
Python

# 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
# cffi - required cffi versions (implemented within pure module)
# cffi-allow - allow pure Python implementation if cffi version is missing
# py - only load pure Python modules
#
# 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"
_packageprefs = {
# policy: (versioned package, pure package)
b"c": (r"cext", None),
b"allow": (r"cext", r"pure"),
b"cffi": (r"cffi", None),
b"cffi-allow": (r"cffi", r"pure"),
b"py": (None, r"pure"),
}
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.
if r"__pypy__" in sys.builtin_module_names:
policy = b"cffi"
# Our C extensions aren't yet compatible with Python 3. So use pure Python
# on Python 3 for now.
if sys.version_info[0] >= 3:
policy = b"py"
# Environment variable can always force settings.
if sys.version_info[0] >= 3:
if r"HGMODULEPOLICY" in os.environ:
policy = os.environ[r"HGMODULEPOLICY"].encode(r"utf-8")
else:
policy = os.environ.get(r"HGMODULEPOLICY", policy)
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]
# keep in sync with "version" in C modules
_cextversions = {
(r"cext", r"base85"): 1,
(r"cext", r"bdiff"): 1,
(r"cext", r"diffhelpers"): 1,
(r"cext", r"mpatch"): 1,
(r"cext", r"osutil"): 2,
(r"cext", r"parsers"): 4,
}
# map import request to other package or module
_modredirects = {
(r"cext", r"charencode"): (r"cext", r"parsers"),
(r"cffi", r"base85"): (r"pure", r"base85"),
(r"cffi", r"charencode"): (r"pure", r"charencode"),
(r"cffi", r"diffhelpers"): (r"pure", r"diffhelpers"),
(r"cffi", r"parsers"): (r"pure", r"parsers"),
}
def _checkmod(pkgname, modname, mod):
expected = _cextversions.get((pkgname, modname))
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:
pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
try:
mod = _importfrom(pn, mn)
if pn == verpkg:
_checkmod(pn, mn, mod)
return mod
except ImportError:
if not purepkg:
raise
pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
return _importfrom(pn, mn)