summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2021-11-06 13:30:21 -0400
committerJason R. Coombs <jaraco@jaraco.com>2021-11-06 13:31:30 -0400
commit10035d4a24de28537eb8eb2849175e334bb0393b (patch)
treea38c6f644609c64f00e23ec07984cd382b987426
parentaf44971ccc28f5151c896eec66b801944cf8545b (diff)
parent5c836a504b7f040e2ebb09172802e7364b070ddc (diff)
downloadpython-setuptools-git-10035d4a24de28537eb8eb2849175e334bb0393b.tar.gz
Merge branch 'main' into feature/local-schemes
-rw-r--r--.github/workflows/main.yml42
-rw-r--r--README.rst37
-rw-r--r--distutils/_msvccompiler.py2
-rw-r--r--distutils/ccompiler.py7
-rw-r--r--distutils/command/build.py2
-rw-r--r--distutils/command/build_ext.py10
-rw-r--r--distutils/command/build_py.py26
-rw-r--r--distutils/command/build_scripts.py10
-rw-r--r--distutils/command/install.py29
-rw-r--r--distutils/cygwinccompiler.py91
-rw-r--r--distutils/filelist.py62
-rw-r--r--distutils/msvc9compiler.py4
-rw-r--r--distutils/msvccompiler.py4
-rw-r--r--distutils/spawn.py27
-rw-r--r--distutils/sysconfig.py23
-rw-r--r--distutils/tests/test_build_ext.py2
-rw-r--r--distutils/tests/test_filelist.py10
-rw-r--r--distutils/tests/test_sysconfig.py17
-rw-r--r--distutils/tests/test_unixccompiler.py101
-rw-r--r--distutils/unixccompiler.py37
-rw-r--r--distutils/util.py136
-rw-r--r--docs/distutils/apiref.rst18
22 files changed, 388 insertions, 309 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..6a8ff006
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,42 @@
+name: tests
+
+on: [push, pull_request]
+
+jobs:
+ test:
+ strategy:
+ matrix:
+ python: [3.6, 3.8, 3.9]
+ platform: [ubuntu-latest, macos-latest, windows-latest]
+ runs-on: ${{ matrix.platform }}
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python }}
+ - name: Install tox
+ run: |
+ python -m pip install tox
+ - name: Run tests
+ run: tox
+
+ release:
+ needs: test
+ if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.9
+ - name: Install tox
+ run: |
+ python -m pip install tox
+ - name: Release
+ run: tox -e release
+ env:
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.rst b/README.rst
index 76dd0791..588898bb 100644
--- a/README.rst
+++ b/README.rst
@@ -3,42 +3,7 @@ Python Module Distribution Utilities extracted from the Python Standard Library
Synchronizing
=============
-This project is kept in sync with the code still in stdlib.
-
-From CPython
-------------
-
-The original history and attribution of all changes contributed to CPython can be found in the `cpython branch <https://github.com/pypa/distutils/tree/cpython>`_. If new commits are added to CPython, they should be synchronized back to this project.
-
-First, create a clone of CPython that only includes the distutils changes. Due to the large size of the CPython repository, this operation is fairly expensive.
-
-::
-
- git clone https://github.com/python/cpython python-distutils
- cd python-distutils
- git filter-branch --prune-empty --subdirectory-filter Lib/distutils master
-
-Then, pull those changes into the repository at the cpython branch.
-
-::
-
- cd $distutils
- git checkout cpython
- git fetch $python_distutils
- git merge FETCH_HEAD
-
-Finally, merge the changes from cpython into master (possibly as a pull request).
-
-To CPython
-----------
-
-Merging changes from this repository is easier.
-
-From the CPython repo, cherry-pick the changes from this project.
-
-::
-
- git -C $distutils format-patch HEAD~2 --stdout | git am --directory Lib
+This project is no longer kept in sync with the code still in stdlib, which is deprecated and scheduled for removal.
To Setuptools
-------------
diff --git a/distutils/_msvccompiler.py b/distutils/_msvccompiler.py
index e9af4cf5..b7a06082 100644
--- a/distutils/_msvccompiler.py
+++ b/distutils/_msvccompiler.py
@@ -248,7 +248,7 @@ class MSVCCompiler(CCompiler) :
# Future releases of Python 3.x will include all past
# versions of vcruntime*.dll for compatibility.
self.compile_options = [
- '/nologo', '/Ox', '/W3', '/GL', '/DNDEBUG', '/MD'
+ '/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD'
]
self.compile_options_debug = [
diff --git a/distutils/ccompiler.py b/distutils/ccompiler.py
index 57bb94e8..b38cf261 100644
--- a/distutils/ccompiler.py
+++ b/distutils/ccompiler.py
@@ -792,6 +792,8 @@ int main (int argc, char **argv) {
objects = self.compile([fname], include_dirs=include_dirs)
except CompileError:
return False
+ finally:
+ os.remove(fname)
try:
self.link_executable(objects, "a.out",
@@ -799,6 +801,11 @@ int main (int argc, char **argv) {
library_dirs=library_dirs)
except (LinkError, TypeError):
return False
+ else:
+ os.remove("a.out")
+ finally:
+ for fn in objects:
+ os.remove(fn)
return True
def find_library_file (self, dirs, lib, debug=0):
diff --git a/distutils/command/build.py b/distutils/command/build.py
index a86df0bc..4355a632 100644
--- a/distutils/command/build.py
+++ b/distutils/command/build.py
@@ -102,7 +102,7 @@ class build(Command):
# particular module distribution -- if user didn't supply it, pick
# one of 'build_purelib' or 'build_platlib'.
if self.build_lib is None:
- if self.distribution.ext_modules:
+ if self.distribution.has_ext_modules():
self.build_lib = self.build_platlib
else:
self.build_lib = self.build_purelib
diff --git a/distutils/command/build_ext.py b/distutils/command/build_ext.py
index bbb34833..22628baf 100644
--- a/distutils/command/build_ext.py
+++ b/distutils/command/build_ext.py
@@ -220,7 +220,7 @@ class build_ext(Command):
# For extensions under Cygwin, Python's library directory must be
# appended to library_dirs
if sys.platform[:6] == 'cygwin':
- if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")):
+ if not sysconfig.python_build:
# building third party extensions
self.library_dirs.append(os.path.join(sys.prefix, "lib",
"python" + get_python_version(),
@@ -690,13 +690,15 @@ class build_ext(Command):
provided, "PyInit_" + module_name. Only relevant on Windows, where
the .pyd file (DLL) must export the module "PyInit_" function.
"""
- suffix = '_' + ext.name.split('.')[-1]
+ name = ext.name.split('.')[-1]
try:
# Unicode module name support as defined in PEP-489
# https://www.python.org/dev/peps/pep-0489/#export-hook-name
- suffix.encode('ascii')
+ name.encode('ascii')
except UnicodeEncodeError:
- suffix = 'U' + suffix.encode('punycode').replace(b'-', b'_').decode('ascii')
+ suffix = 'U_' + name.encode('punycode').replace(b'-', b'_').decode('ascii')
+ else:
+ suffix = "_" + name
initfunc_name = "PyInit" + suffix
if initfunc_name not in ext.export_symbols:
diff --git a/distutils/command/build_py.py b/distutils/command/build_py.py
index edc2171c..7ef9bcef 100644
--- a/distutils/command/build_py.py
+++ b/distutils/command/build_py.py
@@ -9,7 +9,7 @@ import glob
from distutils.core import Command
from distutils.errors import *
-from distutils.util import convert_path, Mixin2to3
+from distutils.util import convert_path
from distutils import log
class build_py (Command):
@@ -390,27 +390,3 @@ class build_py (Command):
if self.optimize > 0:
byte_compile(files, optimize=self.optimize,
force=self.force, prefix=prefix, dry_run=self.dry_run)
-
-class build_py_2to3(build_py, Mixin2to3):
- def run(self):
- self.updated_files = []
-
- # Base class code
- if self.py_modules:
- self.build_modules()
- if self.packages:
- self.build_packages()
- self.build_package_data()
-
- # 2to3
- self.run_2to3(self.updated_files)
-
- # Remaining base class code
- self.byte_compile(self.get_outputs(include_bytecode=0))
-
- def build_module(self, module, module_file, package):
- res = build_py.build_module(self, module, module_file, package)
- if res[1]:
- # file was copied
- self.updated_files.append(res[0])
- return res
diff --git a/distutils/command/build_scripts.py b/distutils/command/build_scripts.py
index ccc70e64..e3312cf0 100644
--- a/distutils/command/build_scripts.py
+++ b/distutils/command/build_scripts.py
@@ -7,7 +7,7 @@ from stat import ST_MODE
from distutils import sysconfig
from distutils.core import Command
from distutils.dep_util import newer
-from distutils.util import convert_path, Mixin2to3
+from distutils.util import convert_path
from distutils import log
import tokenize
@@ -150,11 +150,3 @@ class build_scripts(Command):
os.chmod(file, newmode)
# XXX should we modify self.outfiles?
return outfiles, updated_files
-
-class build_scripts_2to3(build_scripts, Mixin2to3):
-
- def copy_scripts(self):
- outfiles, updated_files = build_scripts.copy_scripts(self)
- if not self.dry_run:
- self.run_2to3(updated_files)
- return outfiles, updated_files
diff --git a/distutils/command/install.py b/distutils/command/install.py
index 0f4ff70c..8161aa9e 100644
--- a/distutils/command/install.py
+++ b/distutils/command/install.py
@@ -30,16 +30,16 @@ WINDOWS_SCHEME = {
INSTALL_SCHEMES = {
'unix_prefix': {
- 'purelib': '{base}/lib/python{py_version_short}/site-packages',
- 'platlib': '{platbase}/{platlibdir}/python{py_version_short}/site-packages',
- 'include': '{base}/include/python{py_version_short}{abiflags}/{dist_name}',
+ 'purelib': '{base}/lib/{implementation_lower}{py_version_short}/site-packages',
+ 'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}/site-packages',
+ 'include': '{base}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}',
'scripts': '{base}/bin',
'data' : '{base}',
},
'unix_home': {
- 'purelib': '{base}/lib/python',
- 'platlib': '{base}/{platlibdir}/python',
- 'include': '{base}/include/python/{dist_name}',
+ 'purelib': '{base}/lib/{implementation_lower}',
+ 'platlib': '{base}/{platlibdir}/{implementation_lower}',
+ 'include': '{base}/include/{implementation_lower}/{dist_name}',
'scripts': '{base}/bin',
'data' : '{base}',
},
@@ -65,8 +65,8 @@ if HAS_USER_SITE:
INSTALL_SCHEMES['nt_user'] = {
'purelib': '{usersite}',
'platlib': '{usersite}',
- 'include': '{userbase}/Python{py_version_nodot}/Include/{dist_name}',
- 'scripts': '{userbase}/Python{py_version_nodot}/Scripts',
+ 'include': '{userbase}/{implementation}{py_version_nodot}/Include/{dist_name}',
+ 'scripts': '{userbase}/{implementation}{py_version_nodot}/Scripts',
'data' : '{userbase}',
}
@@ -74,7 +74,7 @@ if HAS_USER_SITE:
'purelib': '{usersite}',
'platlib': '{usersite}',
'include':
- '{userbase}/include/python{py_version_short}{abiflags}/{dist_name}',
+ '{userbase}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}',
'scripts': '{userbase}/bin',
'data' : '{userbase}',
}
@@ -102,6 +102,12 @@ def _load_schemes():
return schemes
+def _get_implementation():
+ if hasattr(sys, 'pypy_version_info'):
+ return 'PyPy'
+ else:
+ return 'Python'
+
class install(Command):
@@ -336,6 +342,8 @@ class install(Command):
'exec_prefix': exec_prefix,
'abiflags': abiflags,
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
+ 'implementation_lower': _get_implementation().lower(),
+ 'implementation': _get_implementation(),
}
if HAS_USER_SITE:
@@ -371,7 +379,7 @@ class install(Command):
# module distribution is pure or not. Of course, if the user
# already specified install_lib, use their selection.
if self.install_lib is None:
- if self.distribution.ext_modules: # has extensions: non-pure
+ if self.distribution.has_ext_modules(): # has extensions: non-pure
self.install_lib = self.install_platlib
else:
self.install_lib = self.install_purelib
@@ -493,6 +501,7 @@ class install(Command):
"""Sets the install directories by applying the install schemes."""
# it's the caller's problem if they supply a bad name!
if (hasattr(sys, 'pypy_version_info') and
+ sys.version_info < (3, 8) and
not name.endswith(('_user', '_home'))):
if os.name == 'nt':
name = 'pypy_nt'
diff --git a/distutils/cygwinccompiler.py b/distutils/cygwinccompiler.py
index 66c12dd3..f1c38e39 100644
--- a/distutils/cygwinccompiler.py
+++ b/distutils/cygwinccompiler.py
@@ -44,6 +44,8 @@ cygwin in no-cygwin mode).
# (ld supports -shared)
# * mingw gcc 3.2/ld 2.13 works
# (ld supports -shared)
+# * llvm-mingw with Clang 11 works
+# (lld supports -shared)
import os
import sys
@@ -109,41 +111,46 @@ class CygwinCCompiler(UnixCCompiler):
"Compiling may fail because of undefined preprocessor macros."
% details)
- self.gcc_version, self.ld_version, self.dllwrap_version = \
- get_versions()
- self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
- (self.gcc_version,
- self.ld_version,
- self.dllwrap_version) )
-
- # ld_version >= "2.10.90" and < "2.13" should also be able to use
- # gcc -mdll instead of dllwrap
- # Older dllwraps had own version numbers, newer ones use the
- # same as the rest of binutils ( also ld )
- # dllwrap 2.10.90 is buggy
- if self.ld_version >= "2.10.90":
- self.linker_dll = "gcc"
- else:
- self.linker_dll = "dllwrap"
+ self.cc = os.environ.get('CC', 'gcc')
+ self.cxx = os.environ.get('CXX', 'g++')
+
+ if ('gcc' in self.cc): # Start gcc workaround
+ self.gcc_version, self.ld_version, self.dllwrap_version = \
+ get_versions()
+ self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
+ (self.gcc_version,
+ self.ld_version,
+ self.dllwrap_version) )
+
+ # ld_version >= "2.10.90" and < "2.13" should also be able to use
+ # gcc -mdll instead of dllwrap
+ # Older dllwraps had own version numbers, newer ones use the
+ # same as the rest of binutils ( also ld )
+ # dllwrap 2.10.90 is buggy
+ if self.ld_version >= "2.10.90":
+ self.linker_dll = self.cc
+ else:
+ self.linker_dll = "dllwrap"
- # ld_version >= "2.13" support -shared so use it instead of
- # -mdll -static
- if self.ld_version >= "2.13":
+ # ld_version >= "2.13" support -shared so use it instead of
+ # -mdll -static
+ if self.ld_version >= "2.13":
+ shared_option = "-shared"
+ else:
+ shared_option = "-mdll -static"
+ else: # Assume linker is up to date
+ self.linker_dll = self.cc
shared_option = "-shared"
- else:
- shared_option = "-mdll -static"
- # Hard-code GCC because that's what this is all about.
- # XXX optimization, warnings etc. should be customizable.
- self.set_executables(compiler='gcc -mcygwin -O -Wall',
- compiler_so='gcc -mcygwin -mdll -O -Wall',
- compiler_cxx='g++ -mcygwin -O -Wall',
- linker_exe='gcc -mcygwin',
+ self.set_executables(compiler='%s -mcygwin -O -Wall' % self.cc,
+ compiler_so='%s -mcygwin -mdll -O -Wall' % self.cc,
+ compiler_cxx='%s -mcygwin -O -Wall' % self.cxx,
+ linker_exe='%s -mcygwin' % self.cc,
linker_so=('%s -mcygwin %s' %
(self.linker_dll, shared_option)))
# cygwin and mingw32 need different sets of libraries
- if self.gcc_version == "2.91.57":
+ if ('gcc' in self.cc and self.gcc_version == "2.91.57"):
# cygwin shouldn't need msvcrt, but without the dlls will crash
# (gcc version 2.91.57) -- perhaps something about initialization
self.dll_libraries=["msvcrt"]
@@ -281,26 +288,26 @@ class Mingw32CCompiler(CygwinCCompiler):
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
- if self.ld_version >= "2.13":
- shared_option = "-shared"
- else:
+ if ('gcc' in self.cc and self.ld_version < "2.13"):
shared_option = "-mdll -static"
+ else:
+ shared_option = "-shared"
# A real mingw32 doesn't need to specify a different entry point,
# but cygwin 2.91.57 in no-cygwin-mode needs it.
- if self.gcc_version <= "2.91.57":
+ if ('gcc' in self.cc and self.gcc_version <= "2.91.57"):
entry_point = '--entry _DllMain@12'
else:
entry_point = ''
- if is_cygwingcc():
+ if is_cygwincc(self.cc):
raise CCompilerError(
'Cygwin gcc cannot be used with --compiler=mingw32')
- self.set_executables(compiler='gcc -O -Wall',
- compiler_so='gcc -mdll -O -Wall',
- compiler_cxx='g++ -O -Wall',
- linker_exe='gcc',
+ self.set_executables(compiler='%s -O -Wall' % self.cc,
+ compiler_so='%s -mdll -O -Wall' % self.cc,
+ compiler_cxx='%s -O -Wall' % self.cxx,
+ linker_exe='%s' % self.cc,
linker_so='%s %s %s'
% (self.linker_dll, shared_option,
entry_point))
@@ -351,6 +358,10 @@ def check_config_h():
if "GCC" in sys.version:
return CONFIG_H_OK, "sys.version mentions 'GCC'"
+ # Clang would also work
+ if "Clang" in sys.version:
+ return CONFIG_H_OK, "sys.version mentions 'Clang'"
+
# let's see if __GNUC__ is mentioned in python.h
fn = sysconfig.get_config_h_filename()
try:
@@ -397,7 +408,7 @@ def get_versions():
commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
return tuple([_find_exe_version(cmd) for cmd in commands])
-def is_cygwingcc():
- '''Try to determine if the gcc that would be used is from cygwin.'''
- out_string = check_output(['gcc', '-dumpmachine'])
+def is_cygwincc(cc):
+ '''Try to determine if the compiler that would be used is from cygwin.'''
+ out_string = check_output([cc, '-dumpmachine'])
return out_string.strip().endswith(b'cygwin')
diff --git a/distutils/filelist.py b/distutils/filelist.py
index c92d5fdb..82a77384 100644
--- a/distutils/filelist.py
+++ b/distutils/filelist.py
@@ -4,13 +4,16 @@ Provides the FileList class, used for poking about the filesystem
and building lists of files.
"""
-import os, re
+import os
+import re
import fnmatch
import functools
+
from distutils.util import convert_path
from distutils.errors import DistutilsTemplateError, DistutilsInternalError
from distutils import log
+
class FileList:
"""A list of files built by on exploring the filesystem and filtered by
applying various patterns to what we find there.
@@ -46,7 +49,7 @@ class FileList:
if DEBUG:
print(msg)
- # -- List-like methods ---------------------------------------------
+ # Collection methods
def append(self, item):
self.files.append(item)
@@ -61,8 +64,7 @@ class FileList:
for sort_tuple in sortable_files:
self.files.append(os.path.join(*sort_tuple))
-
- # -- Other miscellaneous utility methods ---------------------------
+ # Other miscellaneous utility methods
def remove_duplicates(self):
# Assumes list has been sorted!
@@ -70,8 +72,7 @@ class FileList:
if self.files[i] == self.files[i - 1]:
del self.files[i]
-
- # -- "File template" methods ---------------------------------------
+ # "File template" methods
def _parse_template_line(self, line):
words = line.split()
@@ -146,9 +147,11 @@ class FileList:
(dir, ' '.join(patterns)))
for pattern in patterns:
if not self.include_pattern(pattern, prefix=dir):
- log.warn(("warning: no files found matching '%s' "
- "under directory '%s'"),
- pattern, dir)
+ msg = (
+ "warning: no files found matching '%s' "
+ "under directory '%s'"
+ )
+ log.warn(msg, pattern, dir)
elif action == 'recursive-exclude':
self.debug_print("recursive-exclude %s %s" %
@@ -174,8 +177,7 @@ class FileList:
raise DistutilsInternalError(
"this cannot happen: invalid action '%s'" % action)
-
- # -- Filtering/selection methods -----------------------------------
+ # Filtering/selection methods
def include_pattern(self, pattern, anchor=1, prefix=None, is_regex=0):
"""Select strings (presumably filenames) from 'self.files' that
@@ -219,9 +221,8 @@ class FileList:
files_found = True
return files_found
-
- def exclude_pattern (self, pattern,
- anchor=1, prefix=None, is_regex=0):
+ def exclude_pattern(
+ self, pattern, anchor=1, prefix=None, is_regex=0):
"""Remove strings (presumably filenames) from 'files' that match
'pattern'. Other parameters are the same as for
'include_pattern()', above.
@@ -240,21 +241,47 @@ class FileList:
return files_found
-# ----------------------------------------------------------------------
# Utility functions
def _find_all_simple(path):
"""
Find all files under 'path'
"""
+ all_unique = _UniqueDirs.filter(os.walk(path, followlinks=True))
results = (
os.path.join(base, file)
- for base, dirs, files in os.walk(path, followlinks=True)
+ for base, dirs, files in all_unique
for file in files
)
return filter(os.path.isfile, results)
+class _UniqueDirs(set):
+ """
+ Exclude previously-seen dirs from walk results,
+ avoiding infinite recursion.
+ Ref https://bugs.python.org/issue44497.
+ """
+ def __call__(self, walk_item):
+ """
+ Given an item from an os.walk result, determine
+ if the item represents a unique dir for this instance
+ and if not, prevent further traversal.
+ """
+ base, dirs, files = walk_item
+ stat = os.stat(base)
+ candidate = stat.st_dev, stat.st_ino
+ found = candidate in self
+ if found:
+ del dirs[:]
+ self.add(candidate)
+ return not found
+
+ @classmethod
+ def filter(cls, items):
+ return filter(cls(), items)
+
+
def findall(dir=os.curdir):
"""
Find all files under 'dir' and return the list of full filenames.
@@ -319,7 +346,8 @@ def translate_pattern(pattern, anchor=1, prefix=None, is_regex=0):
if os.sep == '\\':
sep = r'\\'
pattern_re = pattern_re[len(start): len(pattern_re) - len(end)]
- pattern_re = r'%s\A%s%s.*%s%s' % (start, prefix_re, sep, pattern_re, end)
+ pattern_re = r'%s\A%s%s.*%s%s' % (
+ start, prefix_re, sep, pattern_re, end)
else: # no prefix -- respect anchor flag
if anchor:
pattern_re = r'%s\A%s' % (start, pattern_re[len(start):])
diff --git a/distutils/msvc9compiler.py b/distutils/msvc9compiler.py
index 6934e964..a1b3b02f 100644
--- a/distutils/msvc9compiler.py
+++ b/distutils/msvc9compiler.py
@@ -399,13 +399,13 @@ class MSVCCompiler(CCompiler) :
self.preprocess_options = None
if self.__arch == "x86":
- self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
+ self.compile_options = [ '/nologo', '/O2', '/MD', '/W3',
'/DNDEBUG']
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
'/Z7', '/D_DEBUG']
else:
# Win64
- self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
+ self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GS-' ,
'/DNDEBUG']
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
'/Z7', '/D_DEBUG']
diff --git a/distutils/msvccompiler.py b/distutils/msvccompiler.py
index d5857cb1..2d447b85 100644
--- a/distutils/msvccompiler.py
+++ b/distutils/msvccompiler.py
@@ -283,13 +283,13 @@ class MSVCCompiler(CCompiler) :
self.preprocess_options = None
if self.__arch == "Intel":
- self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
+ self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GX' ,
'/DNDEBUG']
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
'/Z7', '/D_DEBUG']
else:
# Win64
- self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
+ self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GS-' ,
'/DNDEBUG']
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
'/Z7', '/D_DEBUG']
diff --git a/distutils/spawn.py b/distutils/spawn.py
index a73b8b9b..6e1c89f1 100644
--- a/distutils/spawn.py
+++ b/distutils/spawn.py
@@ -15,11 +15,6 @@ from distutils.debug import DEBUG
from distutils import log
-if sys.platform == 'darwin':
- _cfg_target = None
- _cfg_target_split = None
-
-
def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):
"""Run another program, specified as a command list 'cmd', in a new process.
@@ -52,24 +47,10 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):
env = env if env is not None else dict(os.environ)
if sys.platform == 'darwin':
- global _cfg_target, _cfg_target_split
- if _cfg_target is None:
- from distutils import sysconfig
- _cfg_target = sysconfig.get_config_var(
- 'MACOSX_DEPLOYMENT_TARGET') or ''
- if _cfg_target:
- _cfg_target_split = [int(x) for x in _cfg_target.split('.')]
- if _cfg_target:
- # ensure that the deployment target of build process is not less
- # than that used when the interpreter was built. This ensures
- # extension modules are built with correct compatibility values
- cur_target = os.environ.get('MACOSX_DEPLOYMENT_TARGET', _cfg_target)
- if _cfg_target_split > [int(x) for x in cur_target.split('.')]:
- my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: '
- 'now "%s" but "%s" during configure'
- % (cur_target, _cfg_target))
- raise DistutilsPlatformError(my_msg)
- env.update(MACOSX_DEPLOYMENT_TARGET=cur_target)
+ from distutils.util import MACOSX_VERSION_VAR, get_macosx_target_ver
+ macosx_target_ver = get_macosx_target_ver()
+ if macosx_target_ver:
+ env[MACOSX_VERSION_VAR] = macosx_target_ver
try:
proc = subprocess.Popen(cmd, env=env)
diff --git a/distutils/sysconfig.py b/distutils/sysconfig.py
index 879b6981..8832b3ec 100644
--- a/distutils/sysconfig.py
+++ b/distutils/sysconfig.py
@@ -99,9 +99,9 @@ def get_python_inc(plat_specific=0, prefix=None):
"""
if prefix is None:
prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
- if IS_PYPY:
- return os.path.join(prefix, 'include')
- elif os.name == "posix":
+ if os.name == "posix":
+ if IS_PYPY and sys.version_info < (3, 8):
+ return os.path.join(prefix, 'include')
if python_build:
# Assume the executable is in the build directory. The
# pyconfig.h file should be in the same directory. Since
@@ -113,7 +113,8 @@ def get_python_inc(plat_specific=0, prefix=None):
else:
incdir = os.path.join(get_config_var('srcdir'), 'Include')
return os.path.normpath(incdir)
- python_dir = 'python' + get_python_version() + build_flags
+ implementation = 'pypy' if IS_PYPY else 'python'
+ python_dir = implementation + get_python_version() + build_flags
return os.path.join(prefix, "include", python_dir)
elif os.name == "nt":
if python_build:
@@ -142,7 +143,8 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
If 'prefix' is supplied, use it instead of sys.base_prefix or
sys.base_exec_prefix -- i.e., ignore 'plat_specific'.
"""
- if IS_PYPY:
+
+ if IS_PYPY and sys.version_info < (3, 8):
# PyPy-specific schema
if prefix is None:
prefix = PREFIX
@@ -164,8 +166,9 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
else:
# Pure Python
libdir = "lib"
+ implementation = 'pypy' if IS_PYPY else 'python'
libpython = os.path.join(prefix, libdir,
- "python" + get_python_version())
+ implementation + get_python_version())
if standard_lib:
return libpython
else:
@@ -211,10 +214,9 @@ def customize_compiler(compiler):
if 'CC' in os.environ:
newcc = os.environ['CC']
- if (sys.platform == 'darwin'
- and 'LDSHARED' not in os.environ
+ if('LDSHARED' not in os.environ
and ldshared.startswith(cc)):
- # On OS X, if CC is overridden, use that as the default
+ # If CC is overridden, use that as the default
# command for LDSHARED as well
ldshared = newcc + ldshared[len(cc):]
cc = newcc
@@ -252,6 +254,9 @@ def customize_compiler(compiler):
linker_exe=cc,
archiver=archiver)
+ if 'RANLIB' in os.environ and compiler.executables.get('ranlib', None):
+ compiler.set_executables(ranlib=os.environ['RANLIB'])
+
compiler.shared_lib_extension = shlib_suffix
diff --git a/distutils/tests/test_build_ext.py b/distutils/tests/test_build_ext.py
index 5a72458c..85ecf4b7 100644
--- a/distutils/tests/test_build_ext.py
+++ b/distutils/tests/test_build_ext.py
@@ -316,7 +316,7 @@ class BuildExtTestCase(TempdirManager,
self.assertRegex(cmd.get_ext_filename(modules[0].name), r'foo(_d)?\..*')
self.assertRegex(cmd.get_ext_filename(modules[1].name), r'föö(_d)?\..*')
self.assertEqual(cmd.get_export_symbols(modules[0]), ['PyInit_foo'])
- self.assertEqual(cmd.get_export_symbols(modules[1]), ['PyInitU_f_gkaa'])
+ self.assertEqual(cmd.get_export_symbols(modules[1]), ['PyInitU_f_1gaa'])
def test_compiler_option(self):
# cmd.compiler is an option and
diff --git a/distutils/tests/test_filelist.py b/distutils/tests/test_filelist.py
index d8e4b39f..9ec507b5 100644
--- a/distutils/tests/test_filelist.py
+++ b/distutils/tests/test_filelist.py
@@ -331,6 +331,16 @@ class FindAllTestCase(unittest.TestCase):
expected = [file1]
self.assertEqual(filelist.findall(temp_dir), expected)
+ @os_helper.skip_unless_symlink
+ def test_symlink_loop(self):
+ with os_helper.temp_dir() as temp_dir:
+ link = os.path.join(temp_dir, 'link-to-parent')
+ content = os.path.join(temp_dir, 'somefile')
+ os_helper.create_empty_file(content)
+ os.symlink('.', link)
+ files = filelist.findall(temp_dir)
+ assert len(files) == 1
+
def test_suite():
return unittest.TestSuite([
diff --git a/distutils/tests/test_sysconfig.py b/distutils/tests/test_sysconfig.py
index c7571942..80cd1599 100644
--- a/distutils/tests/test_sysconfig.py
+++ b/distutils/tests/test_sysconfig.py
@@ -9,6 +9,7 @@ import unittest
from distutils import sysconfig
from distutils.ccompiler import get_default_compiler
+from distutils.unixccompiler import UnixCCompiler
from distutils.tests import support
from test.support import run_unittest, swap_item
@@ -84,9 +85,14 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
# make sure AR gets caught
class compiler:
compiler_type = 'unix'
+ executables = UnixCCompiler.executables
+
+ def __init__(self):
+ self.exes = {}
def set_executables(self, **kw):
- self.exes = kw
+ for k, v in kw.items():
+ self.exes[k] = v
sysconfig_vars = {
'AR': 'sc_ar',
@@ -125,6 +131,7 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
os.environ['ARFLAGS'] = '--env-arflags'
os.environ['CFLAGS'] = '--env-cflags'
os.environ['CPPFLAGS'] = '--env-cppflags'
+ os.environ['RANLIB'] = 'env_ranlib'
comp = self.customize_compiler()
self.assertEqual(comp.exes['archiver'],
@@ -145,6 +152,12 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
' --env-cppflags'))
self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix')
+ if sys.platform == "darwin":
+ self.assertEqual(comp.exes['ranlib'],
+ 'env_ranlib')
+ else:
+ self.assertTrue('ranlib' not in comp.exes)
+
del os.environ['AR']
del os.environ['CC']
del os.environ['CPP']
@@ -154,6 +167,7 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
del os.environ['ARFLAGS']
del os.environ['CFLAGS']
del os.environ['CPPFLAGS']
+ del os.environ['RANLIB']
comp = self.customize_compiler()
self.assertEqual(comp.exes['archiver'],
@@ -171,6 +185,7 @@ class SysconfigTestCase(support.EnvironGuard, unittest.TestCase):
self.assertEqual(comp.exes['linker_so'],
'sc_ldshared')
self.assertEqual(comp.shared_lib_extension, 'sc_shutil_suffix')
+ self.assertTrue('ranlib' not in comp.exes)
def test_parse_makefile_base(self):
self.makefile = TESTFN
diff --git a/distutils/tests/test_unixccompiler.py b/distutils/tests/test_unixccompiler.py
index 1828ba1a..ee2fe99c 100644
--- a/distutils/tests/test_unixccompiler.py
+++ b/distutils/tests/test_unixccompiler.py
@@ -1,4 +1,5 @@
"""Tests for distutils.unixccompiler."""
+import os
import sys
import unittest
from test.support import run_unittest
@@ -6,7 +7,9 @@ from test.support import run_unittest
from .py38compat import EnvironmentVarGuard
from distutils import sysconfig
+from distutils.errors import DistutilsPlatformError
from distutils.unixccompiler import UnixCCompiler
+from distutils.util import _clear_cached_macosx_ver
class UnixCCompilerTestCase(unittest.TestCase):
@@ -26,18 +29,90 @@ class UnixCCompilerTestCase(unittest.TestCase):
@unittest.skipIf(sys.platform == 'win32', "can't test on Windows")
def test_runtime_libdir_option(self):
- # Issue#5900
+ # Issue #5900; GitHub Issue #37
#
# Ensure RUNPATH is added to extension modules with RPATH if
# GNU ld is used
# darwin
sys.platform = 'darwin'
- self.assertEqual(self.cc.rpath_foo(), '-L/foo')
+ darwin_ver_var = 'MACOSX_DEPLOYMENT_TARGET'
+ darwin_rpath_flag = '-Wl,-rpath,/foo'
+ darwin_lib_flag = '-L/foo'
+
+ # (macOS version from syscfg, macOS version from env var) -> flag
+ # Version value of None generates two tests: as None and as empty string
+ # Expected flag value of None means an mismatch exception is expected
+ darwin_test_cases = [
+ ((None , None ), darwin_lib_flag),
+ ((None , '11' ), darwin_rpath_flag),
+ (('10' , None ), darwin_lib_flag),
+ (('10.3' , None ), darwin_lib_flag),
+ (('10.3.1', None ), darwin_lib_flag),
+ (('10.5' , None ), darwin_rpath_flag),
+ (('10.5.1', None ), darwin_rpath_flag),
+ (('10.3' , '10.3' ), darwin_lib_flag),
+ (('10.3' , '10.5' ), darwin_rpath_flag),
+ (('10.5' , '10.3' ), darwin_lib_flag),
+ (('10.5' , '11' ), darwin_rpath_flag),
+ (('10.4' , '10' ), None),
+ ]
+
+ def make_darwin_gcv(syscfg_macosx_ver):
+ def gcv(var):
+ if var == darwin_ver_var:
+ return syscfg_macosx_ver
+ return "xxx"
+ return gcv
+
+ def do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag):
+ env = os.environ
+ msg = "macOS version = (sysconfig=%r, env=%r)" % \
+ (syscfg_macosx_ver, env_macosx_ver)
+
+ # Save
+ old_gcv = sysconfig.get_config_var
+ old_env_macosx_ver = env.get(darwin_ver_var)
+
+ # Setup environment
+ _clear_cached_macosx_ver()
+ sysconfig.get_config_var = make_darwin_gcv(syscfg_macosx_ver)
+ if env_macosx_ver is not None:
+ env[darwin_ver_var] = env_macosx_ver
+ elif darwin_ver_var in env:
+ env.pop(darwin_ver_var)
+
+ # Run the test
+ if expected_flag is not None:
+ self.assertEqual(self.cc.rpath_foo(), expected_flag, msg=msg)
+ else:
+ with self.assertRaisesRegex(DistutilsPlatformError,
+ darwin_ver_var + r' mismatch', msg=msg):
+ self.cc.rpath_foo()
+
+ # Restore
+ if old_env_macosx_ver is not None:
+ env[darwin_ver_var] = old_env_macosx_ver
+ elif darwin_ver_var in env:
+ env.pop(darwin_ver_var)
+ sysconfig.get_config_var = old_gcv
+ _clear_cached_macosx_ver()
+
+ for macosx_vers, expected_flag in darwin_test_cases:
+ syscfg_macosx_ver, env_macosx_ver = macosx_vers
+ do_darwin_test(syscfg_macosx_ver, env_macosx_ver, expected_flag)
+ # Bonus test cases with None interpreted as empty string
+ if syscfg_macosx_ver is None:
+ do_darwin_test("", env_macosx_ver, expected_flag)
+ if env_macosx_ver is None:
+ do_darwin_test(syscfg_macosx_ver, "", expected_flag)
+ if syscfg_macosx_ver is None and env_macosx_ver is None:
+ do_darwin_test("", "", expected_flag)
+
+ old_gcv = sysconfig.get_config_var
# hp-ux
sys.platform = 'hp-ux'
- old_gcv = sysconfig.get_config_var
def gcv(v):
return 'xxx'
sysconfig.get_config_var = gcv
@@ -65,6 +140,14 @@ class UnixCCompilerTestCase(unittest.TestCase):
sysconfig.get_config_var = gcv
self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo')
+ def gcv(v):
+ if v == 'CC':
+ return 'gcc -pthread -B /bar'
+ elif v == 'GNULD':
+ return 'yes'
+ sysconfig.get_config_var = gcv
+ self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo')
+
# GCC non-GNULD
sys.platform = 'bar'
def gcv(v):
@@ -94,7 +177,7 @@ class UnixCCompilerTestCase(unittest.TestCase):
elif v == 'GNULD':
return 'yes'
sysconfig.get_config_var = gcv
- self.assertEqual(self.cc.rpath_foo(), '-R/foo')
+ self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo')
# non-GCC non-GNULD
sys.platform = 'bar'
@@ -104,10 +187,10 @@ class UnixCCompilerTestCase(unittest.TestCase):
elif v == 'GNULD':
return 'no'
sysconfig.get_config_var = gcv
- self.assertEqual(self.cc.rpath_foo(), '-R/foo')
+ self.assertEqual(self.cc.rpath_foo(), '-Wl,-R/foo')
- @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X')
- def test_osx_cc_overrides_ldshared(self):
+ @unittest.skipIf(sys.platform == 'win32', "can't test on Windows")
+ def test_cc_overrides_ldshared(self):
# Issue #18080:
# ensure that setting CC env variable also changes default linker
def gcv(v):
@@ -127,8 +210,8 @@ class UnixCCompilerTestCase(unittest.TestCase):
sysconfig.customize_compiler(self.cc)
self.assertEqual(self.cc.linker_so[0], 'my_cc')
- @unittest.skipUnless(sys.platform == 'darwin', 'test only relevant for OS X')
- def test_osx_explicit_ldshared(self):
+ @unittest.skipIf(sys.platform == 'win32', "can't test on Windows")
+ def test_explicit_ldshared(self):
# Issue #18080:
# ensure that setting CC env variable does not change
# explicit LDSHARED setting for linker
diff --git a/distutils/unixccompiler.py b/distutils/unixccompiler.py
index 4d7a6de7..a07e5988 100644
--- a/distutils/unixccompiler.py
+++ b/distutils/unixccompiler.py
@@ -13,7 +13,7 @@ the "typical" Unix-style command-line C compiler:
* link shared library handled by 'cc -shared'
"""
-import os, sys, re
+import os, sys, re, shlex
from distutils import sysconfig
from distutils.dep_util import newer
@@ -231,33 +231,30 @@ class UnixCCompiler(CCompiler):
# this time, there's no way to determine this information from
# the configuration data stored in the Python installation, so
# we use this hack.
- compiler = os.path.basename(sysconfig.get_config_var("CC"))
+ compiler = os.path.basename(shlex.split(sysconfig.get_config_var("CC"))[0])
if sys.platform[:6] == "darwin":
- # MacOSX's linker doesn't understand the -R flag at all
- return "-L" + dir
+ from distutils.util import get_macosx_target_ver, split_version
+ macosx_target_ver = get_macosx_target_ver()
+ if macosx_target_ver and split_version(macosx_target_ver) >= [10, 5]:
+ return "-Wl,-rpath," + dir
+ else: # no support for -rpath on earlier macOS versions
+ return "-L" + dir
elif sys.platform[:7] == "freebsd":
return "-Wl,-rpath=" + dir
elif sys.platform[:5] == "hp-ux":
if self._is_gcc(compiler):
return ["-Wl,+s", "-L" + dir]
return ["+s", "-L" + dir]
+
+ # For all compilers, `-Wl` is the presumed way to
+ # pass a compiler option to the linker and `-R` is
+ # the way to pass an RPATH.
+ if sysconfig.get_config_var("GNULD") == "yes":
+ # GNU ld needs an extra option to get a RUNPATH
+ # instead of just an RPATH.
+ return "-Wl,--enable-new-dtags,-R" + dir
else:
- if self._is_gcc(compiler):
- # gcc on non-GNU systems does not need -Wl, but can
- # use it anyway. Since distutils has always passed in
- # -Wl whenever gcc was used in the past it is probably
- # safest to keep doing so.
- if sysconfig.get_config_var("GNULD") == "yes":
- # GNU ld needs an extra option to get a RUNPATH
- # instead of just an RPATH.
- return "-Wl,--enable-new-dtags,-R" + dir
- else:
- return "-Wl,-R" + dir
- else:
- # No idea how --enable-new-dtags would be passed on to
- # ld if this system was using GNU ld. Don't know if a
- # system like this even exists.
- return "-R" + dir
+ return "-Wl,-R" + dir
def library_option(self, lib):
return "-l" + lib
diff --git a/distutils/util.py b/distutils/util.py
index 81d6869f..d9916a0a 100644
--- a/distutils/util.py
+++ b/distutils/util.py
@@ -103,11 +103,66 @@ def get_platform():
'x86' : 'win32',
'x64' : 'win-amd64',
'arm' : 'win-arm32',
+ 'arm64': 'win-arm64',
}
return TARGET_TO_PLAT.get(os.environ.get('VSCMD_ARG_TGT_ARCH')) or get_host_platform()
else:
return get_host_platform()
+
+if sys.platform == 'darwin':
+ _syscfg_macosx_ver = None # cache the version pulled from sysconfig
+MACOSX_VERSION_VAR = 'MACOSX_DEPLOYMENT_TARGET'
+
+def _clear_cached_macosx_ver():
+ """For testing only. Do not call."""
+ global _syscfg_macosx_ver
+ _syscfg_macosx_ver = None
+
+def get_macosx_target_ver_from_syscfg():
+ """Get the version of macOS latched in the Python interpreter configuration.
+ Returns the version as a string or None if can't obtain one. Cached."""
+ global _syscfg_macosx_ver
+ if _syscfg_macosx_ver is None:
+ from distutils import sysconfig
+ ver = sysconfig.get_config_var(MACOSX_VERSION_VAR) or ''
+ if ver:
+ _syscfg_macosx_ver = ver
+ return _syscfg_macosx_ver
+
+def get_macosx_target_ver():
+ """Return the version of macOS for which we are building.
+
+ The target version defaults to the version in sysconfig latched at time
+ the Python interpreter was built, unless overridden by an environment
+ variable. If neither source has a value, then None is returned"""
+
+ syscfg_ver = get_macosx_target_ver_from_syscfg()
+ env_ver = os.environ.get(MACOSX_VERSION_VAR)
+
+ if env_ver:
+ # Validate overridden version against sysconfig version, if have both.
+ # Ensure that the deployment target of the build process is not less
+ # than 10.3 if the interpreter was built for 10.3 or later. This
+ # ensures extension modules are built with correct compatibility
+ # values, specifically LDSHARED which can use
+ # '-undefined dynamic_lookup' which only works on >= 10.3.
+ if syscfg_ver and split_version(syscfg_ver) >= [10, 3] and \
+ split_version(env_ver) < [10, 3]:
+ my_msg = ('$' + MACOSX_VERSION_VAR + ' mismatch: '
+ 'now "%s" but "%s" during configure; '
+ 'must use 10.3 or later'
+ % (env_ver, syscfg_ver))
+ raise DistutilsPlatformError(my_msg)
+ return env_ver
+ return syscfg_ver
+
+
+def split_version(s):
+ """Convert a dot-separated string into a list of numbers for comparisons"""
+ return [int(n) for n in s.split('.')]
+
+
def convert_path (pathname):
"""Return 'pathname' as a name that will work on the native filesystem,
i.e. split it on '/' and put it back together again using the current
@@ -491,84 +546,3 @@ def rfc822_escape (header):
lines = header.split('\n')
sep = '\n' + 8 * ' '
return sep.join(lines)
-
-# 2to3 support
-
-def run_2to3(files, fixer_names=None, options=None, explicit=None):
- """Invoke 2to3 on a list of Python files.
- The files should all come from the build area, as the
- modification is done in-place. To reduce the build time,
- only files modified since the last invocation of this
- function should be passed in the files argument."""
-
- if not files:
- return
-
- # Make this class local, to delay import of 2to3
- from lib2to3.refactor import RefactoringTool, get_fixers_from_package
- class DistutilsRefactoringTool(RefactoringTool):
- def log_error(self, msg, *args, **kw):
- log.error(msg, *args)
-
- def log_message(self, msg, *args):
- log.info(msg, *args)
-
- def log_debug(self, msg, *args):
- log.debug(msg, *args)
-
- if fixer_names is None:
- fixer_names = get_fixers_from_package('lib2to3.fixes')
- r = DistutilsRefactoringTool(fixer_names, options=options)
- r.refactor(files, write=True)
-
-def copydir_run_2to3(src, dest, template=None, fixer_names=None,
- options=None, explicit=None):
- """Recursively copy a directory, only copying new and changed files,
- running run_2to3 over all newly copied Python modules afterward.
-
- If you give a template string, it's parsed like a MANIFEST.in.
- """
- from distutils.dir_util import mkpath
- from distutils.file_util import copy_file
- from distutils.filelist import FileList
- filelist = FileList()
- curdir = os.getcwd()
- os.chdir(src)
- try:
- filelist.findall()
- finally:
- os.chdir(curdir)
- filelist.files[:] = filelist.allfiles
- if template:
- for line in template.splitlines():
- line = line.strip()
- if not line: continue
- filelist.process_template_line(line)
- copied = []
- for filename in filelist.files:
- outname = os.path.join(dest, filename)
- mkpath(os.path.dirname(outname))
- res = copy_file(os.path.join(src, filename), outname, update=1)
- if res[1]: copied.append(outname)
- run_2to3([fn for fn in copied if fn.lower().endswith('.py')],
- fixer_names=fixer_names, options=options, explicit=explicit)
- return copied
-
-class Mixin2to3:
- '''Mixin class for commands that run 2to3.
- To configure 2to3, setup scripts may either change
- the class variables, or inherit from individual commands
- to override how 2to3 is invoked.'''
-
- # provide list of fixers to run;
- # defaults to all from lib2to3.fixers
- fixer_names = None
-
- # options dictionary
- options = None
-
- # list of fixers to invoke even though they are marked as explicit
- explicit = None
-
- def run_2to3(self, files):
- return run_2to3(files, self.fixer_names, self.options, self.explicit)
diff --git a/docs/distutils/apiref.rst b/docs/distutils/apiref.rst
index b14197c2..372755a8 100644
--- a/docs/distutils/apiref.rst
+++ b/docs/distutils/apiref.rst
@@ -1940,24 +1940,6 @@ Subclasses of :class:`Command` must define the following methods.
.. class:: build_py
-.. class:: build_py_2to3
-
- Alternative implementation of build_py which also runs the
- 2to3 conversion library on each .py file that is going to be
- installed. To use this in a setup.py file for a distribution
- that is designed to run with both Python 2.x and 3.x, add::
-
- try:
- from distutils.command.build_py import build_py_2to3 as build_py
- except ImportError:
- from distutils.command.build_py import build_py
-
- to your setup.py, and later::
-
- cmdclass = {'build_py': build_py}
-
- to the invocation of setup().
-
:mod:`distutils.command.build_scripts` --- Build the scripts of a package
=========================================================================