Commit b3b67519 authored by Jason R. Coombs's avatar Jason R. Coombs

Merge monkeypatch-module

parents c550d2d9 857c16bb
......@@ -2,6 +2,11 @@
CHANGES
=======
v27.1.0
-------
* Introduce the (private) ``monkey`` module to encapsulate
the distutils monkeypatching behavior.
v27.0.0
-------
......
"""Extensions to the 'distutils' for large or complex distributions"""
import os
import sys
import functools
import distutils.core
import distutils.filelist
from distutils.core import Command as _Command
from distutils.util import convert_path
from fnmatch import fnmatchcase
......@@ -13,8 +11,9 @@ from setuptools.extern.six.moves import filterfalse, map
import setuptools.version
from setuptools.extension import Extension
from setuptools.dist import Distribution, Feature, _get_unpatched
from setuptools.dist import Distribution, Feature
from setuptools.depends import Require
from . import monkey
__all__ = [
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
......@@ -122,7 +121,7 @@ find_packages = PackageFinder.find
setup = distutils.core.setup
_Command = _get_unpatched(_Command)
_Command = monkey.get_unpatched(distutils.core.Command)
class Command(_Command):
......@@ -144,10 +143,6 @@ class Command(_Command):
return cmd
# we can't patch distutils.cmd, alas
distutils.core.Command = Command
def _find_all_simple(path):
"""
Find all files under 'path'
......@@ -172,31 +167,4 @@ def findall(dir=os.curdir):
return list(files)
has_issue_12885 = (
sys.version_info < (3, 4, 6)
or
(3, 5) < sys.version_info <= (3, 5, 3)
or
(3, 6) < sys.version_info
)
if has_issue_12885:
# fix findall bug in distutils (http://bugs.python.org/issue12885)
distutils.filelist.findall = findall
needs_warehouse = (
sys.version_info < (2, 7, 13)
or
(3, 0) < sys.version_info < (3, 3, 7)
or
(3, 4) < sys.version_info < (3, 4, 6)
or
(3, 5) < sys.version_info <= (3, 5, 3)
or
(3, 6) < sys.version_info
)
if needs_warehouse:
warehouse = 'https://upload.pypi.org/legacy/'
distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse
monkey.patch_all()
......@@ -2,14 +2,12 @@ __all__ = ['Distribution']
import re
import os
import sys
import warnings
import numbers
import distutils.log
import distutils.core
import distutils.cmd
import distutils.dist
from distutils.core import Distribution as _Distribution
from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
DistutilsSetupError)
from distutils.util import rfc822_escape
......@@ -20,100 +18,66 @@ from pkg_resources.extern import packaging
from setuptools.depends import Require
from setuptools import windows_support
from setuptools.monkey import get_unpatched
import pkg_resources
def _get_unpatched(cls):
"""Protect against re-patching the distutils if reloaded
warnings.warn("Do not call this function", DeprecationWarning)
return get_unpatched(cls)
Also ensures that no other distutils extension monkeypatched the distutils
first.
"""
while cls.__module__.startswith('setuptools'):
cls, = cls.__bases__
if not cls.__module__.startswith('distutils'):
raise AssertionError(
"distutils has already been patched by %r" % cls
)
return cls
_Distribution = _get_unpatched(_Distribution)
def _patch_distribution_metadata_write_pkg_file():
"""Patch write_pkg_file to also write Requires-Python/Requires-External"""
# Based on Python 3.5 version
def write_pkg_file(self, file):
"""Write the PKG-INFO format data to a file object.
"""
version = '1.0'
if (self.provides or self.requires or self.obsoletes or
self.classifiers or self.download_url):
version = '1.1'
# Setuptools specific for PEP 345
if hasattr(self, 'python_requires'):
version = '1.2'
file.write('Metadata-Version: %s\n' % version)
file.write('Name: %s\n' % self.get_name())
file.write('Version: %s\n' % self.get_version())
file.write('Summary: %s\n' % self.get_description())
file.write('Home-page: %s\n' % self.get_url())
file.write('Author: %s\n' % self.get_contact())
file.write('Author-email: %s\n' % self.get_contact_email())
file.write('License: %s\n' % self.get_license())
if self.download_url:
file.write('Download-URL: %s\n' % self.download_url)
long_desc = rfc822_escape(self.get_long_description())
file.write('Description: %s\n' % long_desc)
keywords = ','.join(self.get_keywords())
if keywords:
file.write('Keywords: %s\n' % keywords)
self._write_list(file, 'Platform', self.get_platforms())
self._write_list(file, 'Classifier', self.get_classifiers())
# PEP 314
self._write_list(file, 'Requires', self.get_requires())
self._write_list(file, 'Provides', self.get_provides())
self._write_list(file, 'Obsoletes', self.get_obsoletes())
# Setuptools specific for PEP 345
if hasattr(self, 'python_requires'):
file.write('Requires-Python: %s\n' % self.python_requires)
distutils.dist.DistributionMetadata.write_pkg_file = write_pkg_file
_patch_distribution_metadata_write_pkg_file()
def _patch_distribution_metadata_write_pkg_info():
# Based on Python 3.5 version
def write_pkg_file(self, file):
"""Write the PKG-INFO format data to a file object.
"""
Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
correct this undesirable behavior.
version = '1.0'
if (self.provides or self.requires or self.obsoletes or
self.classifiers or self.download_url):
version = '1.1'
# Setuptools specific for PEP 345
if hasattr(self, 'python_requires'):
version = '1.2'
file.write('Metadata-Version: %s\n' % version)
file.write('Name: %s\n' % self.get_name())
file.write('Version: %s\n' % self.get_version())
file.write('Summary: %s\n' % self.get_description())
file.write('Home-page: %s\n' % self.get_url())
file.write('Author: %s\n' % self.get_contact())
file.write('Author-email: %s\n' % self.get_contact_email())
file.write('License: %s\n' % self.get_license())
if self.download_url:
file.write('Download-URL: %s\n' % self.download_url)
long_desc = rfc822_escape(self.get_long_description())
file.write('Description: %s\n' % long_desc)
keywords = ','.join(self.get_keywords())
if keywords:
file.write('Keywords: %s\n' % keywords)
self._write_list(file, 'Platform', self.get_platforms())
self._write_list(file, 'Classifier', self.get_classifiers())
# PEP 314
self._write_list(file, 'Requires', self.get_requires())
self._write_list(file, 'Provides', self.get_provides())
self._write_list(file, 'Obsoletes', self.get_obsoletes())
# Setuptools specific for PEP 345
if hasattr(self, 'python_requires'):
file.write('Requires-Python: %s\n' % self.python_requires)
# from Python 3.4
def write_pkg_info(self, base_dir):
"""Write the PKG-INFO file into the release tree.
"""
environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
if not environment_local:
return
# from Python 3.4
def write_pkg_info(self, base_dir):
"""Write the PKG-INFO file into the release tree.
"""
with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
encoding='UTF-8') as pkg_info:
self.write_pkg_file(pkg_info)
with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
encoding='UTF-8') as pkg_info:
self.write_pkg_file(pkg_info)
distutils.dist.DistributionMetadata.write_pkg_info = write_pkg_info
_patch_distribution_metadata_write_pkg_info()
sequence = tuple, list
......@@ -245,6 +209,9 @@ def check_packages(dist, attr, value):
)
_Distribution = get_unpatched(distutils.core.Distribution)
class Distribution(_Distribution):
"""Distribution with support for features, tests, and package data
......@@ -792,11 +759,6 @@ class Distribution(_Distribution):
sys.stdout.detach(), encoding, errors, newline, line_buffering)
# Install it throughout the distutils
for module in distutils.dist, distutils.core, distutils.cmd:
module.Distribution = Distribution
class Feature:
"""
**deprecated** -- The `Feature` facility was never completely implemented
......
import sys
import re
import functools
import distutils.core
......@@ -7,12 +6,7 @@ import distutils.extension
from setuptools.extern.six.moves import map
from .dist import _get_unpatched
from . import msvc
_Extension = _get_unpatched(distutils.core.Extension)
msvc.patch_for_specialized_compiler()
from .monkey import get_unpatched
def _have_cython():
......@@ -33,6 +27,9 @@ def _have_cython():
have_pyrex = _have_cython
_Extension = get_unpatched(distutils.core.Extension)
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
......@@ -59,9 +56,3 @@ class Extension(_Extension):
class Library(Extension):
"""Just like a regular Extension, but built as a library instead"""
distutils.core.Extension = Extension
distutils.extension.Extension = Extension
if 'distutils.command.build_ext' in sys.modules:
sys.modules['distutils.command.build_ext'].Extension = Extension
"""
Monkey patching of distutils.
"""
import sys
import distutils.filelist
import platform
import setuptools
__all__ = []
"""
Everything is private. Contact the project team
if you think you need this functionality.
"""
def get_unpatched(cls):
"""Protect against re-patching the distutils if reloaded
Also ensures that no other distutils extension monkeypatched the distutils
first.
"""
while cls.__module__.startswith('setuptools'):
cls, = cls.__bases__
if not cls.__module__.startswith('distutils'):
raise AssertionError(
"distutils has already been patched by %r" % cls
)
return cls
def patch_all():
# we can't patch distutils.cmd, alas
distutils.core.Command = setuptools.Command
has_issue_12885 = (
sys.version_info < (3, 4, 6)
or
(3, 5) < sys.version_info <= (3, 5, 3)
or
(3, 6) < sys.version_info
)
if has_issue_12885:
# fix findall bug in distutils (http://bugs.python.org/issue12885)
distutils.filelist.findall = setuptools.findall
needs_warehouse = (
sys.version_info < (2, 7, 13)
or
(3, 0) < sys.version_info < (3, 3, 7)
or
(3, 4) < sys.version_info < (3, 4, 6)
or
(3, 5) < sys.version_info <= (3, 5, 3)
or
(3, 6) < sys.version_info
)
if needs_warehouse:
warehouse = 'https://upload.pypi.org/legacy/'
distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse
_patch_distribution_metadata_write_pkg_file()
_patch_distribution_metadata_write_pkg_info()
# Install Distribution throughout the distutils
for module in distutils.dist, distutils.core, distutils.cmd:
module.Distribution = setuptools.dist.Distribution
# Install the patched Extension
distutils.core.Extension = setuptools.extension.Extension
distutils.extension.Extension = setuptools.extension.Extension
if 'distutils.command.build_ext' in sys.modules:
sys.modules['distutils.command.build_ext'].Extension = (
setuptools.extension.Extension
)
patch_for_msvc_specialized_compiler()
def _patch_distribution_metadata_write_pkg_file():
"""Patch write_pkg_file to also write Requires-Python/Requires-External"""
distutils.dist.DistributionMetadata.write_pkg_file = (
setuptools.dist.write_pkg_file
)
def _patch_distribution_metadata_write_pkg_info():
"""
Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
correct this undesirable behavior.
"""
environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
if not environment_local:
return
distutils.dist.DistributionMetadata.write_pkg_info = (
setuptools.dist.write_pkg_info
)
unpatched = dict()
def patch_for_msvc_specialized_compiler():
"""
Patch functions in distutils to use standalone Microsoft Visual C++
compilers.
"""
try:
# Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4)
import distutils.msvc9compiler as msvc9compiler
except ImportError:
pass
try:
# Distutil file for MSVC++ 14.0 and upper (Python 3.5+)
import distutils._msvccompiler as msvc14compiler
except ImportError:
pass
if platform.system() != 'Windows':
# Compilers only availables on Microsoft Windows
return
if unpatched:
# Already patched
return
try:
# Patch distutils.msvc9compiler
unpatched['msvc9_find_vcvarsall'] = msvc9compiler.find_vcvarsall
msvc9compiler.find_vcvarsall = msvc9_find_vcvarsall
unpatched['msvc9_query_vcvarsall'] = msvc9compiler.query_vcvarsall
msvc9compiler.query_vcvarsall = msvc9_query_vcvarsall
except NameError:
pass
try:
# Patch distutils._msvccompiler._get_vc_env
unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env
msvc14compiler._get_vc_env = msvc14_get_vc_env
except NameError:
pass
try:
# Patch distutils._msvccompiler.gen_lib_options for Numpy
unpatched['msvc14_gen_lib_options'] = msvc14compiler.gen_lib_options
msvc14compiler.gen_lib_options = msvc14_gen_lib_options
except NameError:
pass
"""
This module adds improved support for Microsoft Visual C++ compilers.
Improved support for Microsoft Visual C++ compilers.
Known supported compilers:
--------------------------
Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64);
Microsoft Windows SDK 7.0 (x86, x64, ia64);
Microsoft Windows SDK 6.1 (x86, x64, ia64)
Microsoft Visual C++ 10.0:
Microsoft Windows SDK 7.1 (x86, x64, ia64)
Microsoft Visual C++ 14.0:
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
"""
import os
import sys
import platform
......@@ -10,6 +24,8 @@ from pkg_resources.extern.packaging.version import LegacyVersion
from setuptools.extern.six.moves import filterfalse
from . import monkey
if platform.system() == 'Windows':
from setuptools.extern.six.moves import winreg
safe_env = os.environ
......@@ -26,74 +42,10 @@ else:
safe_env = dict()
try:
# Distutil file for MSVC++ 9.0 and upper (Python 2.7 to 3.4)
import distutils.msvc9compiler as msvc9compiler
from distutils.msvc9compiler import Reg
except ImportError:
pass
try:
# Distutil file for MSVC++ 14.0 and upper (Python 3.5+)
import distutils._msvccompiler as msvc14compiler
except ImportError:
pass
unpatched = dict()
def patch_for_specialized_compiler():
"""
Patch functions in distutils to use standalone Microsoft Visual C++
compilers.
Known supported compilers:
--------------------------
Microsoft Visual C++ 9.0:
Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64);
Microsoft Windows SDK 7.0 (x86, x64, ia64);
Microsoft Windows SDK 6.1 (x86, x64, ia64)
Microsoft Visual C++ 10.0:
Microsoft Windows SDK 7.1 (x86, x64, ia64)
Microsoft Visual C++ 14.0:
Microsoft Visual C++ Build Tools 2015 (x86, x64, arm)
"""
if platform.system() != 'Windows':
# Compilers only availables on Microsoft Windows
return
if 'distutils' not in globals():
# The module isn't available to be patched
return
if unpatched:
# Already patched
return
try:
# Patch distutils.msvc9compiler
unpatched['msvc9_find_vcvarsall'] = msvc9compiler.find_vcvarsall
msvc9compiler.find_vcvarsall = msvc9_find_vcvarsall
unpatched['msvc9_query_vcvarsall'] = msvc9compiler.query_vcvarsall
msvc9compiler.query_vcvarsall = msvc9_query_vcvarsall
except NameError:
pass
try:
# Patch distutils._msvccompiler._get_vc_env
unpatched['msvc14_get_vc_env'] = msvc14compiler._get_vc_env
msvc14compiler._get_vc_env = msvc14_get_vc_env
except NameError:
pass
try:
# Patch distutils._msvccompiler.gen_lib_options for Numpy
unpatched['msvc14_gen_lib_options'] = msvc14compiler.gen_lib_options
msvc14compiler.gen_lib_options = msvc14_gen_lib_options
except NameError:
pass
def msvc9_find_vcvarsall(version):
"""
......@@ -117,7 +69,6 @@ def msvc9_find_vcvarsall(version):
------
vcvarsall.bat path: str
"""
Reg = msvc9compiler.Reg
VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
key = VC_BASE % ('', version)
try:
......@@ -136,7 +87,7 @@ def msvc9_find_vcvarsall(version):
if os.path.isfile(vcvarsall):
return vcvarsall
return unpatched['msvc9_find_vcvarsall'](version)
return monkey.unpatched['msvc9_find_vcvarsall'](version)
def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
......@@ -169,7 +120,8 @@ def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs):
"""
# Try to get environement from vcvarsall.bat (Classical way)
try:
return unpatched['msvc9_query_vcvarsall'](ver, arch, *args, **kwargs)
orig = monkey.unpatched['msvc9_query_vcvarsall']
return orig(ver, arch, *args, **kwargs)
except distutils.errors.DistutilsPlatformError:
# Pass error if Vcvarsall.bat is missing
pass
......@@ -208,7 +160,7 @@ def msvc14_get_vc_env(plat_spec):
"""
# Try to get environment from vcvarsall.bat (Classical way)
try:
return unpatched['msvc14_get_vc_env'](plat_spec)
return monkey.unpatched['msvc14_get_vc_env'](plat_spec)
except distutils.errors.DistutilsPlatformError:
# Pass error Vcvarsall.bat is missing
pass
......@@ -231,7 +183,7 @@ def msvc14_gen_lib_options(*args, **kwargs):
import numpy as np
if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'):
return np.distutils.ccompiler.gen_lib_options(*args, **kwargs)
return unpatched['msvc14_gen_lib_options'](*args, **kwargs)
return monkey.unpatched['msvc14_gen_lib_options'](*args, **kwargs)
def _augment_exception(exc, version, arch=''):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment