From e371422476f51a83d27d70dc45bbfba1544aad55 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 19 Jul 2020 21:36:33 -0400 Subject: Consolidate distutils importing hacks into _distutils_importer package. Generate distutils-precedence.pth inline. --- MANIFEST.in | 1 - _distutils_importer/__init__.py | 19 +++++++++++-- _distutils_importer/install.py | 5 ++++ _distutils_importer/override.py | 47 +++++++++++++++++++++++++++++++ conftest.py | 2 +- distutils_precedence.pth | 1 - setup.py | 8 ++---- setuptools/__init__.py | 3 +- setuptools/distutils_patch.py | 61 ----------------------------------------- 9 files changed, 72 insertions(+), 75 deletions(-) create mode 100644 _distutils_importer/install.py create mode 100644 _distutils_importer/override.py delete mode 100644 distutils_precedence.pth delete mode 100644 setuptools/distutils_patch.py diff --git a/MANIFEST.in b/MANIFEST.in index be83a7f3..128ae280 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -13,5 +13,4 @@ include launcher.c include msvc-build-launcher.cmd include pytest.ini include tox.ini -include distutils_precedence.pth exclude pyproject.toml # Temporary workaround for #1644. diff --git a/_distutils_importer/__init__.py b/_distutils_importer/__init__.py index 323ae203..ffa4caea 100644 --- a/_distutils_importer/__init__.py +++ b/_distutils_importer/__init__.py @@ -1,4 +1,20 @@ +""" +Ensure that the local copy of distutils is preferred over stdlib. + +See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 +for more motivation. +""" + import sys +import os + + +def enabled(): + """ + Allow selection of distutils by environment variable. + """ + which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib') + return which == 'local' class DistutilsMetaFinder: @@ -34,6 +50,3 @@ def remove_shim(): sys.path.remove(DISTUTILS_FINDER) except ValueError: pass - - -add_shim() diff --git a/_distutils_importer/install.py b/_distutils_importer/install.py new file mode 100644 index 00000000..73f13b29 --- /dev/null +++ b/_distutils_importer/install.py @@ -0,0 +1,5 @@ +from . import enabled, add_shim + + +if enabled(): + add_shim() diff --git a/_distutils_importer/override.py b/_distutils_importer/override.py new file mode 100644 index 00000000..91738485 --- /dev/null +++ b/_distutils_importer/override.py @@ -0,0 +1,47 @@ +import sys +import re +import importlib +import warnings + +from . import enabled + + +is_pypy = '__pypy__' in sys.builtin_module_names + + +def warn_distutils_present(): + if 'distutils' not in sys.modules: + return + if is_pypy and sys.version_info < (3, 7): + # PyPy for 3.6 unconditionally imports distutils, so bypass the warning + # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 + return + warnings.warn( + "Distutils was imported before Setuptools. This usage is discouraged " + "and may exhibit undesirable behaviors or errors. Please use " + "Setuptools' objects directly or at least import Setuptools first.") + + +def clear_distutils(): + if 'distutils' not in sys.modules: + return + warnings.warn("Setuptools is replacing distutils.") + mods = [name for name in sys.modules if re.match(r'distutils\b', name)] + for name in mods: + del sys.modules[name] + + +def ensure_local_distutils(): + clear_distutils() + distutils = importlib.import_module('setuptools._distutils') + distutils.__name__ = 'distutils' + sys.modules['distutils'] = distutils + + # sanity check that submodules load as expected + core = importlib.import_module('distutils.core') + assert '_distutils' in core.__file__, core.__file__ + + +warn_distutils_present() +if enabled(): + ensure_local_distutils() diff --git a/conftest.py b/conftest.py index 6013e187..868bf5be 100644 --- a/conftest.py +++ b/conftest.py @@ -15,7 +15,7 @@ collect_ignore = [ 'tests/manual_test.py', 'setuptools/tests/mod_with_constant.py', 'setuptools/_distutils', - 'setuptools/distutils_patch.py', + '_distutils_importer', ] diff --git a/distutils_precedence.pth b/distutils_precedence.pth deleted file mode 100644 index 2d9b996a..00000000 --- a/distutils_precedence.pth +++ /dev/null @@ -1 +0,0 @@ -import os; (os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib') == 'local' and __import__('_distutils_importer')) diff --git a/setup.py b/setup.py index cba37d3e..a6e1abc4 100755 --- a/setup.py +++ b/setup.py @@ -94,12 +94,8 @@ class install_with_pth(install): def initialize_options(self): install.initialize_options(self) - - name = 'distutils_precedence' - with open(os.path.join(here, name + '.pth'), 'rt') as f: - contents = f.read() - - self.extra_path = (name, contents) + self.extra_path = ( + 'distutils-precedence', 'import _distutils_importer.install') def finalize_options(self): install.finalize_options(self) diff --git a/setuptools/__init__.py b/setuptools/__init__.py index d9740403..80b287b4 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -5,8 +5,7 @@ import functools import os import re -# Disabled for now due to: #2228, #2230 -import setuptools.distutils_patch # noqa: F401 +import _distutils_importer.override # noqa: F401 import distutils.core from distutils.errors import DistutilsOptionError diff --git a/setuptools/distutils_patch.py b/setuptools/distutils_patch.py deleted file mode 100644 index 33f1e7f9..00000000 --- a/setuptools/distutils_patch.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -Ensure that the local copy of distutils is preferred over stdlib. - -See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 -for more motivation. -""" - -import sys -import re -import os -import importlib -import warnings - - -is_pypy = '__pypy__' in sys.builtin_module_names - - -def warn_distutils_present(): - if 'distutils' not in sys.modules: - return - if is_pypy and sys.version_info < (3, 7): - # PyPy for 3.6 unconditionally imports distutils, so bypass the warning - # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 - return - warnings.warn( - "Distutils was imported before Setuptools. This usage is discouraged " - "and may exhibit undesirable behaviors or errors. Please use " - "Setuptools' objects directly or at least import Setuptools first.") - - -def clear_distutils(): - if 'distutils' not in sys.modules: - return - warnings.warn("Setuptools is replacing distutils.") - mods = [name for name in sys.modules if re.match(r'distutils\b', name)] - for name in mods: - del sys.modules[name] - - -def enabled(): - """ - Allow selection of distutils by environment variable. - """ - which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib') - return which == 'local' - - -def ensure_local_distutils(): - clear_distutils() - distutils = importlib.import_module('setuptools._distutils') - distutils.__name__ = 'distutils' - sys.modules['distutils'] = distutils - - # sanity check that submodules load as expected - core = importlib.import_module('distutils.core') - assert '_distutils' in core.__file__, core.__file__ - - -warn_distutils_present() -if enabled(): - ensure_local_distutils() -- cgit v1.2.3