mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-07 12:26:52 +00:00
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
This commit is contained in:
parent
72ad6dc953
commit
f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions
|
|
@ -1,23 +1,22 @@
|
|||
"""Extensions to the 'distutils' for large or complex distributions"""
|
||||
from __future__ import annotations
|
||||
|
||||
from fnmatch import fnmatchcase
|
||||
import functools
|
||||
import os
|
||||
import re
|
||||
from fnmatch import fnmatchcase
|
||||
|
||||
import _distutils_hack.override # noqa: F401
|
||||
|
||||
import distutils.core
|
||||
import setuptools.version
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.util import convert_path
|
||||
|
||||
from ._deprecation_warning import SetuptoolsDeprecationWarning
|
||||
|
||||
import setuptools.version
|
||||
from setuptools.extension import Extension
|
||||
from setuptools.dist import Distribution
|
||||
from setuptools.depends import Require
|
||||
from setuptools.dist import Distribution
|
||||
from setuptools.extension import Extension
|
||||
|
||||
from . import monkey
|
||||
from ._deprecation_warning import SetuptoolsDeprecationWarning
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
@ -64,7 +63,7 @@ class PackageFinder:
|
|||
convert_path(where),
|
||||
cls._build_filter('ez_setup', '*__pycache__', *exclude),
|
||||
cls._build_filter(*include),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
@ -179,7 +178,7 @@ class Command(_Command):
|
|||
return default
|
||||
elif not isinstance(val, str):
|
||||
raise DistutilsOptionError(
|
||||
"'%s' must be a %s (got `%s`)" % (option, what, val)
|
||||
"'{}' must be a {} (got `{}`)".format(option, what, val),
|
||||
)
|
||||
return val
|
||||
|
||||
|
|
@ -201,7 +200,7 @@ class Command(_Command):
|
|||
ok = False
|
||||
if not ok:
|
||||
raise DistutilsOptionError(
|
||||
"'%s' must be a list of strings (got %r)" % (option, val)
|
||||
"'{}' must be a list of strings (got {!r})".format(option, val),
|
||||
)
|
||||
|
||||
def reinitialize_command(self, command, reinit_subcommands=0, **kw):
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
|
||||
class SetuptoolsDeprecationWarning(Warning):
|
||||
"""
|
||||
Base class for warning deprecations in ``setuptools``
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ used from a setup script as
|
|||
|
||||
setup (...)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
|
|
|
|||
|
|
@ -6,38 +6,39 @@ for Microsoft Visual Studio 2015.
|
|||
The module is compatible with VS 2015 and later. You can find legacy support
|
||||
for older versions in distutils.msvc9compiler and distutils.msvccompiler.
|
||||
"""
|
||||
|
||||
# Written by Perry Stoll
|
||||
# hacked by Robin Becker and Thomas Heller to do a better job of
|
||||
# finding DevStudio (through the registry)
|
||||
# ported to VS 2005 and VS 2008 by Christian Heimes
|
||||
# ported to VS 2015 by Steve Dower
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import subprocess
|
||||
import contextlib
|
||||
import warnings
|
||||
import unittest.mock
|
||||
import warnings
|
||||
with contextlib.suppress(ImportError):
|
||||
import winreg
|
||||
|
||||
from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
|
||||
CompileError, LibError, LinkError
|
||||
CompileError, LibError, LinkError
|
||||
from distutils.ccompiler import CCompiler, gen_lib_options
|
||||
from distutils import log
|
||||
from distutils.util import get_platform
|
||||
|
||||
from itertools import count
|
||||
|
||||
|
||||
def _find_vc2015():
|
||||
try:
|
||||
key = winreg.OpenKeyEx(
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
r"Software\Microsoft\VisualStudio\SxS\VC7",
|
||||
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
|
||||
r'Software\Microsoft\VisualStudio\SxS\VC7',
|
||||
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY,
|
||||
)
|
||||
except OSError:
|
||||
log.debug("Visual C++ is not registered")
|
||||
log.debug('Visual C++ is not registered')
|
||||
return None, None
|
||||
|
||||
best_version = 0
|
||||
|
|
@ -57,6 +58,7 @@ def _find_vc2015():
|
|||
best_version, best_dir = version, vc_dir
|
||||
return best_version, best_dir
|
||||
|
||||
|
||||
def _find_vc2017():
|
||||
"""Returns "15, path" based on the result of invoking vswhere.exe
|
||||
If no install is found, returns "None, None"
|
||||
|
|
@ -67,35 +69,39 @@ def _find_vc2017():
|
|||
If vswhere.exe is not available, by definition, VS 2017 is not
|
||||
installed.
|
||||
"""
|
||||
root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
|
||||
root = os.environ.get('ProgramFiles(x86)') or os.environ.get('ProgramFiles')
|
||||
if not root:
|
||||
return None, None
|
||||
|
||||
try:
|
||||
path = subprocess.check_output([
|
||||
os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
|
||||
"-latest",
|
||||
"-prerelease",
|
||||
"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
|
||||
"-property", "installationPath",
|
||||
"-products", "*",
|
||||
], encoding="mbcs", errors="strict").strip()
|
||||
path = subprocess.check_output(
|
||||
[
|
||||
os.path.join(root, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe'),
|
||||
'-latest',
|
||||
'-prerelease',
|
||||
'-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
|
||||
'-property', 'installationPath',
|
||||
'-products', '*',
|
||||
], encoding='mbcs', errors='strict',
|
||||
).strip()
|
||||
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
|
||||
return None, None
|
||||
|
||||
path = os.path.join(path, "VC", "Auxiliary", "Build")
|
||||
path = os.path.join(path, 'VC', 'Auxiliary', 'Build')
|
||||
if os.path.isdir(path):
|
||||
return 15, path
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
PLAT_SPEC_TO_RUNTIME = {
|
||||
'x86' : 'x86',
|
||||
'x86_amd64' : 'x64',
|
||||
'x86_arm' : 'arm',
|
||||
'x86_arm64' : 'arm64'
|
||||
'x86': 'x86',
|
||||
'x86_amd64': 'x64',
|
||||
'x86_arm': 'arm',
|
||||
'x86_arm64': 'arm64',
|
||||
}
|
||||
|
||||
|
||||
def _find_vcvarsall(plat_spec):
|
||||
# bpo-38597: Removed vcruntime return value
|
||||
_, best_dir = _find_vc2017()
|
||||
|
|
@ -104,18 +110,19 @@ def _find_vcvarsall(plat_spec):
|
|||
best_version, best_dir = _find_vc2015()
|
||||
|
||||
if not best_dir:
|
||||
log.debug("No suitable Visual C++ version found")
|
||||
log.debug('No suitable Visual C++ version found')
|
||||
return None, None
|
||||
|
||||
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
|
||||
vcvarsall = os.path.join(best_dir, 'vcvarsall.bat')
|
||||
if not os.path.isfile(vcvarsall):
|
||||
log.debug("%s cannot be found", vcvarsall)
|
||||
log.debug('%s cannot be found', vcvarsall)
|
||||
return None, None
|
||||
|
||||
return vcvarsall, None
|
||||
|
||||
|
||||
def _get_vc_env(plat_spec):
|
||||
if os.getenv("DISTUTILS_USE_SDK"):
|
||||
if os.getenv('DISTUTILS_USE_SDK'):
|
||||
return {
|
||||
key.lower(): value
|
||||
for key, value in os.environ.items()
|
||||
|
|
@ -123,17 +130,19 @@ def _get_vc_env(plat_spec):
|
|||
|
||||
vcvarsall, _ = _find_vcvarsall(plat_spec)
|
||||
if not vcvarsall:
|
||||
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
|
||||
raise DistutilsPlatformError('Unable to find vcvarsall.bat')
|
||||
|
||||
try:
|
||||
out = subprocess.check_output(
|
||||
'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
|
||||
f'cmd /u /c "{vcvarsall}" {plat_spec} && set',
|
||||
stderr=subprocess.STDOUT,
|
||||
).decode('utf-16le', errors='replace')
|
||||
except subprocess.CalledProcessError as exc:
|
||||
log.error(exc.output)
|
||||
raise DistutilsPlatformError("Error executing {}"
|
||||
.format(exc.cmd))
|
||||
raise DistutilsPlatformError(
|
||||
'Error executing {}'
|
||||
.format(exc.cmd),
|
||||
)
|
||||
|
||||
env = {
|
||||
key.lower(): value
|
||||
|
|
@ -144,6 +153,7 @@ def _get_vc_env(plat_spec):
|
|||
|
||||
return env
|
||||
|
||||
|
||||
def _find_exe(exe, paths=None):
|
||||
"""Return path to an MSVC executable program.
|
||||
|
||||
|
|
@ -161,17 +171,19 @@ def _find_exe(exe, paths=None):
|
|||
return fn
|
||||
return exe
|
||||
|
||||
|
||||
# A map keyed by get_platform() return values to values accepted by
|
||||
# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
|
||||
# lighter-weight MSVC installs that do not include native 64-bit tools.
|
||||
PLAT_TO_VCVARS = {
|
||||
'win32' : 'x86',
|
||||
'win-amd64' : 'x86_amd64',
|
||||
'win-arm32' : 'x86_arm',
|
||||
'win-arm64' : 'x86_arm64'
|
||||
'win32': 'x86',
|
||||
'win-amd64': 'x86_amd64',
|
||||
'win-arm32': 'x86_arm',
|
||||
'win-arm64': 'x86_arm64',
|
||||
}
|
||||
|
||||
class MSVCCompiler(CCompiler) :
|
||||
|
||||
class MSVCCompiler(CCompiler):
|
||||
"""Concrete class that implements an interface to Microsoft Visual C++,
|
||||
as defined by the CCompiler abstract class."""
|
||||
|
||||
|
|
@ -192,8 +204,10 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
# Needed for the filename generation methods provided by the
|
||||
# base class, CCompiler.
|
||||
src_extensions = (_c_extensions + _cpp_extensions +
|
||||
_rc_extensions + _mc_extensions)
|
||||
src_extensions = (
|
||||
_c_extensions + _cpp_extensions +
|
||||
_rc_extensions + _mc_extensions
|
||||
)
|
||||
res_extension = '.res'
|
||||
obj_extension = '.obj'
|
||||
static_lib_extension = '.lib'
|
||||
|
|
@ -201,9 +215,8 @@ class MSVCCompiler(CCompiler) :
|
|||
static_lib_format = shared_lib_format = '%s%s'
|
||||
exe_extension = '.exe'
|
||||
|
||||
|
||||
def __init__(self, verbose=0, dry_run=0, force=0):
|
||||
CCompiler.__init__ (self, verbose, dry_run, force)
|
||||
CCompiler.__init__(self, verbose, dry_run, force)
|
||||
# target platform (.plat_name is consistent with 'bdist')
|
||||
self.plat_name = None
|
||||
self.initialized = False
|
||||
|
|
@ -215,25 +228,29 @@ class MSVCCompiler(CCompiler) :
|
|||
plat_name = get_platform()
|
||||
# sanity check for platforms to prevent obscure errors later.
|
||||
if plat_name not in PLAT_TO_VCVARS:
|
||||
raise DistutilsPlatformError("--plat-name must be one of {}"
|
||||
.format(tuple(PLAT_TO_VCVARS)))
|
||||
raise DistutilsPlatformError(
|
||||
'--plat-name must be one of {}'
|
||||
.format(tuple(PLAT_TO_VCVARS)),
|
||||
)
|
||||
|
||||
# Get the vcvarsall.bat spec for the requested platform.
|
||||
plat_spec = PLAT_TO_VCVARS[plat_name]
|
||||
|
||||
vc_env = _get_vc_env(plat_spec)
|
||||
if not vc_env:
|
||||
raise DistutilsPlatformError("Unable to find a compatible "
|
||||
"Visual Studio installation.")
|
||||
raise DistutilsPlatformError(
|
||||
'Unable to find a compatible '
|
||||
'Visual Studio installation.',
|
||||
)
|
||||
|
||||
self._paths = vc_env.get('path', '')
|
||||
paths = self._paths.split(os.pathsep)
|
||||
self.cc = _find_exe("cl.exe", paths)
|
||||
self.linker = _find_exe("link.exe", paths)
|
||||
self.lib = _find_exe("lib.exe", paths)
|
||||
self.rc = _find_exe("rc.exe", paths) # resource compiler
|
||||
self.mc = _find_exe("mc.exe", paths) # message compiler
|
||||
self.mt = _find_exe("mt.exe", paths) # message compiler
|
||||
self.cc = _find_exe('cl.exe', paths)
|
||||
self.linker = _find_exe('link.exe', paths)
|
||||
self.lib = _find_exe('lib.exe', paths)
|
||||
self.rc = _find_exe('rc.exe', paths) # resource compiler
|
||||
self.mc = _find_exe('mc.exe', paths) # message compiler
|
||||
self.mt = _find_exe('mt.exe', paths) # message compiler
|
||||
|
||||
for dir in vc_env.get('include', '').split(os.pathsep):
|
||||
if dir:
|
||||
|
|
@ -248,19 +265,19 @@ class MSVCCompiler(CCompiler) :
|
|||
# Future releases of Python 3.x will include all past
|
||||
# versions of vcruntime*.dll for compatibility.
|
||||
self.compile_options = [
|
||||
'/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD'
|
||||
'/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD',
|
||||
]
|
||||
|
||||
self.compile_options_debug = [
|
||||
'/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
|
||||
'/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG',
|
||||
]
|
||||
|
||||
ldflags = [
|
||||
'/nologo', '/INCREMENTAL:NO', '/LTCG'
|
||||
'/nologo', '/INCREMENTAL:NO', '/LTCG',
|
||||
]
|
||||
|
||||
ldflags_debug = [
|
||||
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
|
||||
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL',
|
||||
]
|
||||
|
||||
self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
|
||||
|
|
@ -286,10 +303,12 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
# -- Worker methods ------------------------------------------------
|
||||
|
||||
def object_filenames(self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
def object_filenames(
|
||||
self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir='',
|
||||
):
|
||||
ext_map = {
|
||||
**{ext: self.obj_extension for ext in self.src_extensions},
|
||||
**{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
|
||||
|
|
@ -314,19 +333,22 @@ class MSVCCompiler(CCompiler) :
|
|||
# Better to raise an exception instead of silently continuing
|
||||
# and later complain about sources and targets having
|
||||
# different lengths
|
||||
raise CompileError("Don't know how to compile {}".format(p))
|
||||
raise CompileError(f"Don't know how to compile {p}")
|
||||
|
||||
return list(map(make_out_path, source_filenames))
|
||||
|
||||
|
||||
def compile(self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None):
|
||||
def compile(
|
||||
self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
compile_info = self._setup_compile(output_dir, macros, include_dirs,
|
||||
sources, depends, extra_postargs)
|
||||
compile_info = self._setup_compile(
|
||||
output_dir, macros, include_dirs,
|
||||
sources, depends, extra_postargs,
|
||||
)
|
||||
macros, objects, extra_postargs, pp_opts, build = compile_info
|
||||
|
||||
compile_opts = extra_preargs or []
|
||||
|
|
@ -336,7 +358,6 @@ class MSVCCompiler(CCompiler) :
|
|||
else:
|
||||
compile_opts.extend(self.compile_options)
|
||||
|
||||
|
||||
add_cpp_opts = False
|
||||
|
||||
for obj in objects:
|
||||
|
|
@ -351,14 +372,14 @@ class MSVCCompiler(CCompiler) :
|
|||
src = os.path.abspath(src)
|
||||
|
||||
if ext in self._c_extensions:
|
||||
input_opt = "/Tc" + src
|
||||
input_opt = '/Tc' + src
|
||||
elif ext in self._cpp_extensions:
|
||||
input_opt = "/Tp" + src
|
||||
input_opt = '/Tp' + src
|
||||
add_cpp_opts = True
|
||||
elif ext in self._rc_extensions:
|
||||
# compile .RC to .RES file
|
||||
input_opt = src
|
||||
output_opt = "/fo" + obj
|
||||
output_opt = '/fo' + obj
|
||||
try:
|
||||
self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
|
||||
except DistutilsExecError as msg:
|
||||
|
|
@ -381,24 +402,26 @@ class MSVCCompiler(CCompiler) :
|
|||
try:
|
||||
# first compile .MC to .RC and .H file
|
||||
self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
|
||||
base, _ = os.path.splitext(os.path.basename (src))
|
||||
base, _ = os.path.splitext(os.path.basename(src))
|
||||
rc_file = os.path.join(rc_dir, base + '.rc')
|
||||
# then compile .RC to .RES file
|
||||
self.spawn([self.rc, "/fo" + obj, rc_file])
|
||||
self.spawn([self.rc, '/fo' + obj, rc_file])
|
||||
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
continue
|
||||
else:
|
||||
# how to handle this file?
|
||||
raise CompileError("Don't know how to compile {} to {}"
|
||||
.format(src, obj))
|
||||
raise CompileError(
|
||||
"Don't know how to compile {} to {}"
|
||||
.format(src, obj),
|
||||
)
|
||||
|
||||
args = [self.cc] + compile_opts + pp_opts
|
||||
if add_cpp_opts:
|
||||
args.append('/EHsc')
|
||||
args.append(input_opt)
|
||||
args.append("/Fo" + obj)
|
||||
args.append('/Fo' + obj)
|
||||
args.extend(extra_postargs)
|
||||
|
||||
try:
|
||||
|
|
@ -408,72 +431,84 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
return objects
|
||||
|
||||
|
||||
def create_static_lib(self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None):
|
||||
def create_static_lib(
|
||||
self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
objects, output_dir = self._fix_object_args(objects, output_dir)
|
||||
output_filename = self.library_filename(output_libname,
|
||||
output_dir=output_dir)
|
||||
output_filename = self.library_filename(
|
||||
output_libname,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
|
||||
if self._need_link(objects, output_filename):
|
||||
lib_args = objects + ['/OUT:' + output_filename]
|
||||
if debug:
|
||||
pass # XXX what goes here?
|
||||
pass # XXX what goes here?
|
||||
try:
|
||||
log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
|
||||
self.spawn([self.lib] + lib_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise LibError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
|
||||
def link(self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
def link(
|
||||
self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
objects, output_dir = self._fix_object_args(objects, output_dir)
|
||||
fixed_args = self._fix_lib_args(libraries, library_dirs,
|
||||
runtime_library_dirs)
|
||||
fixed_args = self._fix_lib_args(
|
||||
libraries, library_dirs,
|
||||
runtime_library_dirs,
|
||||
)
|
||||
libraries, library_dirs, runtime_library_dirs = fixed_args
|
||||
|
||||
if runtime_library_dirs:
|
||||
self.warn("I don't know what to do with 'runtime_library_dirs': "
|
||||
+ str(runtime_library_dirs))
|
||||
self.warn(
|
||||
"I don't know what to do with 'runtime_library_dirs': " +
|
||||
str(runtime_library_dirs),
|
||||
)
|
||||
|
||||
lib_opts = gen_lib_options(self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
lib_opts = gen_lib_options(
|
||||
self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries,
|
||||
)
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join(output_dir, output_filename)
|
||||
|
||||
if self._need_link(objects, output_filename):
|
||||
ldflags = self._ldflags[target_desc, debug]
|
||||
|
||||
export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
|
||||
export_opts = ['/EXPORT:' + sym for sym in (export_symbols or [])]
|
||||
|
||||
ld_args = (ldflags + lib_opts + export_opts +
|
||||
objects + ['/OUT:' + output_filename])
|
||||
ld_args = (
|
||||
ldflags + lib_opts + export_opts +
|
||||
objects + ['/OUT:' + output_filename]
|
||||
)
|
||||
|
||||
# The MSVC linker generates .lib and .exp files, which cannot be
|
||||
# suppressed by any linker switches. The .lib files may even be
|
||||
|
|
@ -483,11 +518,13 @@ class MSVCCompiler(CCompiler) :
|
|||
build_temp = os.path.dirname(objects[0])
|
||||
if export_symbols is not None:
|
||||
(dll_name, dll_ext) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
os.path.basename(output_filename),
|
||||
)
|
||||
implib_file = os.path.join(
|
||||
build_temp,
|
||||
self.library_filename(dll_name))
|
||||
ld_args.append ('/IMPLIB:' + implib_file)
|
||||
self.library_filename(dll_name),
|
||||
)
|
||||
ld_args.append('/IMPLIB:' + implib_file)
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
|
|
@ -502,7 +539,7 @@ class MSVCCompiler(CCompiler) :
|
|||
except DistutilsExecError as msg:
|
||||
raise LinkError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
def spawn(self, cmd):
|
||||
env = dict(os.environ, PATH=self._paths)
|
||||
|
|
@ -526,7 +563,8 @@ class MSVCCompiler(CCompiler) :
|
|||
else:
|
||||
return
|
||||
warnings.warn(
|
||||
"Fallback spawn triggered. Please update distutils monkeypatch.")
|
||||
'Fallback spawn triggered. Please update distutils monkeypatch.',
|
||||
)
|
||||
with unittest.mock.patch('os.environ', env):
|
||||
bag.value = super().spawn(cmd)
|
||||
|
||||
|
|
@ -535,11 +573,12 @@ class MSVCCompiler(CCompiler) :
|
|||
# ccompiler.py.
|
||||
|
||||
def library_dir_option(self, dir):
|
||||
return "/LIBPATH:" + dir
|
||||
return '/LIBPATH:' + dir
|
||||
|
||||
def runtime_library_dir_option(self, dir):
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to set runtime library search path for MSVC")
|
||||
"don't know how to set runtime library search path for MSVC",
|
||||
)
|
||||
|
||||
def library_option(self, lib):
|
||||
return self.library_filename(lib)
|
||||
|
|
@ -548,7 +587,7 @@ class MSVCCompiler(CCompiler) :
|
|||
# Prefer a debugging library if found (and requested), but deal
|
||||
# with it if we don't have one.
|
||||
if debug:
|
||||
try_names = [lib + "_d", lib]
|
||||
try_names = [lib + '_d', lib]
|
||||
else:
|
||||
try_names = [lib]
|
||||
for dir in dirs:
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
Utility functions for creating archive files (tarballs, zip files,
|
||||
that sort of thing)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from warnings import warn
|
||||
import sys
|
||||
from warnings import warn
|
||||
|
||||
try:
|
||||
import zipfile
|
||||
|
|
@ -28,6 +29,7 @@ try:
|
|||
except ImportError:
|
||||
getgrnam = None
|
||||
|
||||
|
||||
def _get_gid(name):
|
||||
"""Returns a gid, given a group name."""
|
||||
if getgrnam is None or name is None:
|
||||
|
|
@ -40,6 +42,7 @@ def _get_gid(name):
|
|||
return result[2]
|
||||
return None
|
||||
|
||||
|
||||
def _get_uid(name):
|
||||
"""Returns an uid, given a user name."""
|
||||
if getpwnam is None or name is None:
|
||||
|
|
@ -52,8 +55,11 @@ def _get_uid(name):
|
|||
return result[2]
|
||||
return None
|
||||
|
||||
def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
|
||||
owner=None, group=None):
|
||||
|
||||
def make_tarball(
|
||||
base_name, base_dir, compress='gzip', verbose=0, dry_run=0,
|
||||
owner=None, group=None,
|
||||
):
|
||||
"""Create a (possibly compressed) tar file from all the files under
|
||||
'base_dir'.
|
||||
|
||||
|
|
@ -69,16 +75,21 @@ def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
|
|||
|
||||
Returns the output filename.
|
||||
"""
|
||||
tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '',
|
||||
'compress': ''}
|
||||
compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz',
|
||||
'compress': '.Z'}
|
||||
tar_compression = {
|
||||
'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '',
|
||||
'compress': '',
|
||||
}
|
||||
compress_ext = {
|
||||
'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz',
|
||||
'compress': '.Z',
|
||||
}
|
||||
|
||||
# flags for compression program, each element of list will be an argument
|
||||
if compress is not None and compress not in compress_ext.keys():
|
||||
raise ValueError(
|
||||
"bad value for 'compress': must be None, 'gzip', 'bzip2', "
|
||||
"'xz' or 'compress'")
|
||||
"bad value for 'compress': must be None, 'gzip', 'bzip2', "
|
||||
"'xz' or 'compress'",
|
||||
)
|
||||
|
||||
archive_name = base_name + '.tar'
|
||||
if compress != 'compress':
|
||||
|
|
@ -124,6 +135,7 @@ def make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0,
|
|||
|
||||
return archive_name
|
||||
|
||||
|
||||
def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
|
||||
"""Create a zip file from all the files under 'base_dir'.
|
||||
|
||||
|
|
@ -133,38 +145,50 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
|
|||
available, raises DistutilsExecError. Returns the name of the output zip
|
||||
file.
|
||||
"""
|
||||
zip_filename = base_name + ".zip"
|
||||
zip_filename = base_name + '.zip'
|
||||
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
|
||||
|
||||
# If zipfile module is not available, try spawning an external
|
||||
# 'zip' command.
|
||||
if zipfile is None:
|
||||
if verbose:
|
||||
zipoptions = "-r"
|
||||
zipoptions = '-r'
|
||||
else:
|
||||
zipoptions = "-rq"
|
||||
zipoptions = '-rq'
|
||||
|
||||
try:
|
||||
spawn(["zip", zipoptions, zip_filename, base_dir],
|
||||
dry_run=dry_run)
|
||||
spawn(
|
||||
['zip', zipoptions, zip_filename, base_dir],
|
||||
dry_run=dry_run,
|
||||
)
|
||||
except DistutilsExecError:
|
||||
# XXX really should distinguish between "couldn't find
|
||||
# external 'zip' command" and "zip failed".
|
||||
raise DistutilsExecError(("unable to create zip file '%s': "
|
||||
"could neither import the 'zipfile' module nor "
|
||||
"find a standalone zip utility") % zip_filename)
|
||||
raise DistutilsExecError(
|
||||
(
|
||||
"unable to create zip file '%s': "
|
||||
"could neither import the 'zipfile' module nor "
|
||||
'find a standalone zip utility'
|
||||
) % zip_filename,
|
||||
)
|
||||
|
||||
else:
|
||||
log.info("creating '%s' and adding '%s' to it",
|
||||
zip_filename, base_dir)
|
||||
log.info(
|
||||
"creating '%s' and adding '%s' to it",
|
||||
zip_filename, base_dir,
|
||||
)
|
||||
|
||||
if not dry_run:
|
||||
try:
|
||||
zip = zipfile.ZipFile(zip_filename, "w",
|
||||
compression=zipfile.ZIP_DEFLATED)
|
||||
zip = zipfile.ZipFile(
|
||||
zip_filename, 'w',
|
||||
compression=zipfile.ZIP_DEFLATED,
|
||||
)
|
||||
except RuntimeError:
|
||||
zip = zipfile.ZipFile(zip_filename, "w",
|
||||
compression=zipfile.ZIP_STORED)
|
||||
zip = zipfile.ZipFile(
|
||||
zip_filename, 'w',
|
||||
compression=zipfile.ZIP_STORED,
|
||||
)
|
||||
|
||||
with zip:
|
||||
if base_dir != os.curdir:
|
||||
|
|
@ -184,14 +208,16 @@ def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
|
|||
|
||||
return zip_filename
|
||||
|
||||
|
||||
ARCHIVE_FORMATS = {
|
||||
'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"),
|
||||
'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"),
|
||||
'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"),
|
||||
'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"),
|
||||
'tar': (make_tarball, [('compress', None)], "uncompressed tar file"),
|
||||
'zip': (make_zipfile, [],"ZIP file")
|
||||
}
|
||||
'ztar': (make_tarball, [('compress', 'compress')], 'compressed tar file'),
|
||||
'tar': (make_tarball, [('compress', None)], 'uncompressed tar file'),
|
||||
'zip': (make_zipfile, [], 'ZIP file'),
|
||||
}
|
||||
|
||||
|
||||
def check_archive_formats(formats):
|
||||
"""Returns the first format from the 'format' list that is unknown.
|
||||
|
|
@ -203,8 +229,11 @@ def check_archive_formats(formats):
|
|||
return format
|
||||
return None
|
||||
|
||||
def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
|
||||
dry_run=0, owner=None, group=None):
|
||||
|
||||
def make_archive(
|
||||
base_name, format, root_dir=None, base_dir=None, verbose=0,
|
||||
dry_run=0, owner=None, group=None,
|
||||
):
|
||||
"""Create an archive file (eg. zip or tar).
|
||||
|
||||
'base_name' is the name of the file to create, minus any format-specific
|
||||
|
|
|
|||
|
|
@ -3,26 +3,28 @@
|
|||
Contains BorlandCCompiler, an implementation of the abstract CCompiler class
|
||||
for the Borland C++ compiler.
|
||||
"""
|
||||
|
||||
# This implementation by Lyle Johnson, based on the original msvccompiler.py
|
||||
# module and using the directions originally published by Gordon Williams.
|
||||
|
||||
# XXX looks like there's a LOT of overlap between these two classes:
|
||||
# someone should sit down and factor out the common code as
|
||||
# WindowsCCompiler! --GPW
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from distutils.errors import \
|
||||
DistutilsExecError, \
|
||||
CompileError, LibError, LinkError, UnknownFileError
|
||||
from distutils.ccompiler import \
|
||||
CCompiler, gen_preprocess_options
|
||||
from distutils.file_util import write_file
|
||||
from distutils.dep_util import newer
|
||||
from distutils import log
|
||||
|
||||
class BCPPCompiler(CCompiler) :
|
||||
from distutils import log
|
||||
from distutils.ccompiler import CCompiler
|
||||
from distutils.ccompiler import gen_preprocess_options
|
||||
from distutils.dep_util import newer
|
||||
from distutils.errors import CompileError
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.errors import LibError
|
||||
from distutils.errors import LinkError
|
||||
from distutils.errors import UnknownFileError
|
||||
from distutils.file_util import write_file
|
||||
|
||||
|
||||
class BCPPCompiler(CCompiler):
|
||||
"""Concrete class that implements an interface to the Borland C/C++
|
||||
compiler, as defined by the CCompiler abstract class.
|
||||
"""
|
||||
|
|
@ -49,21 +51,22 @@ class BCPPCompiler(CCompiler) :
|
|||
static_lib_format = shared_lib_format = '%s%s'
|
||||
exe_extension = '.exe'
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verbose=0,
|
||||
dry_run=0,
|
||||
force=0,
|
||||
):
|
||||
|
||||
def __init__ (self,
|
||||
verbose=0,
|
||||
dry_run=0,
|
||||
force=0):
|
||||
|
||||
CCompiler.__init__ (self, verbose, dry_run, force)
|
||||
CCompiler.__init__(self, verbose, dry_run, force)
|
||||
|
||||
# These executables are assumed to all be in the path.
|
||||
# Borland doesn't seem to use any special registry settings to
|
||||
# indicate their installation locations.
|
||||
|
||||
self.cc = "bcc32.exe"
|
||||
self.linker = "ilink32.exe"
|
||||
self.lib = "tlib.exe"
|
||||
self.cc = 'bcc32.exe'
|
||||
self.linker = 'ilink32.exe'
|
||||
self.lib = 'tlib.exe'
|
||||
|
||||
self.preprocess_options = None
|
||||
self.compile_options = ['/tWM', '/O2', '/q', '/g0']
|
||||
|
|
@ -73,24 +76,27 @@ class BCPPCompiler(CCompiler) :
|
|||
self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']
|
||||
self.ldflags_static = []
|
||||
self.ldflags_exe = ['/Gn', '/q', '/x']
|
||||
self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r']
|
||||
|
||||
self.ldflags_exe_debug = ['/Gn', '/q', '/x', '/r']
|
||||
|
||||
# -- Worker methods ------------------------------------------------
|
||||
|
||||
def compile(self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None):
|
||||
def compile(
|
||||
self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None,
|
||||
):
|
||||
|
||||
macros, objects, extra_postargs, pp_opts, build = \
|
||||
self._setup_compile(output_dir, macros, include_dirs, sources,
|
||||
depends, extra_postargs)
|
||||
self._setup_compile(
|
||||
output_dir, macros, include_dirs, sources,
|
||||
depends, extra_postargs,
|
||||
)
|
||||
compile_opts = extra_preargs or []
|
||||
compile_opts.append ('-c')
|
||||
compile_opts.append('-c')
|
||||
if debug:
|
||||
compile_opts.extend (self.compile_options_debug)
|
||||
compile_opts.extend(self.compile_options_debug)
|
||||
else:
|
||||
compile_opts.extend (self.compile_options)
|
||||
compile_opts.extend(self.compile_options)
|
||||
|
||||
for obj in objects:
|
||||
try:
|
||||
|
|
@ -106,35 +112,35 @@ class BCPPCompiler(CCompiler) :
|
|||
|
||||
if ext == '.res':
|
||||
# This is already a binary file -- skip it.
|
||||
continue # the 'for' loop
|
||||
continue # the 'for' loop
|
||||
if ext == '.rc':
|
||||
# This needs to be compiled to a .res file -- do it now.
|
||||
try:
|
||||
self.spawn (["brcc32", "-fo", obj, src])
|
||||
self.spawn(['brcc32', '-fo', obj, src])
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
continue # the 'for' loop
|
||||
continue # the 'for' loop
|
||||
|
||||
# The next two are both for the real compiler.
|
||||
if ext in self._c_extensions:
|
||||
input_opt = ""
|
||||
input_opt = ''
|
||||
elif ext in self._cpp_extensions:
|
||||
input_opt = "-P"
|
||||
input_opt = '-P'
|
||||
else:
|
||||
# Unknown file type -- no extra options. The compiler
|
||||
# will probably fail, but let it just in case this is a
|
||||
# file the compiler recognizes even if we don't.
|
||||
input_opt = ""
|
||||
input_opt = ''
|
||||
|
||||
output_opt = "-o" + obj
|
||||
output_opt = '-o' + obj
|
||||
|
||||
# Compiler command line syntax is: "bcc32 [options] file(s)".
|
||||
# Note that the source file names must appear at the end of
|
||||
# the command line.
|
||||
try:
|
||||
self.spawn ([self.cc] + compile_opts + pp_opts +
|
||||
[input_opt, output_opt] +
|
||||
extra_postargs + [src])
|
||||
self.spawn([self.cc] + compile_opts + pp_opts +
|
||||
[input_opt, output_opt] +
|
||||
extra_postargs + [src])
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
|
||||
|
|
@ -142,62 +148,66 @@ class BCPPCompiler(CCompiler) :
|
|||
|
||||
# compile ()
|
||||
|
||||
def create_static_lib(
|
||||
self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
def create_static_lib (self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None):
|
||||
|
||||
(objects, output_dir) = self._fix_object_args (objects, output_dir)
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
output_filename = \
|
||||
self.library_filename (output_libname, output_dir=output_dir)
|
||||
self.library_filename(output_libname, output_dir=output_dir)
|
||||
|
||||
if self._need_link (objects, output_filename):
|
||||
if self._need_link(objects, output_filename):
|
||||
lib_args = [output_filename, '/u'] + objects
|
||||
if debug:
|
||||
pass # XXX what goes here?
|
||||
try:
|
||||
self.spawn ([self.lib] + lib_args)
|
||||
self.spawn([self.lib] + lib_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise LibError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
# create_static_lib ()
|
||||
|
||||
|
||||
def link (self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
def link(
|
||||
self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
# XXX this ignores 'build_temp'! should follow the lead of
|
||||
# msvccompiler.py
|
||||
|
||||
(objects, output_dir) = self._fix_object_args (objects, output_dir)
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
(libraries, library_dirs, runtime_library_dirs) = \
|
||||
self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
|
||||
self._fix_lib_args(libraries, library_dirs, runtime_library_dirs)
|
||||
|
||||
if runtime_library_dirs:
|
||||
log.warn("I don't know what to do with 'runtime_library_dirs': %s",
|
||||
str(runtime_library_dirs))
|
||||
log.warn(
|
||||
"I don't know what to do with 'runtime_library_dirs': %s",
|
||||
str(runtime_library_dirs),
|
||||
)
|
||||
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join (output_dir, output_filename)
|
||||
output_filename = os.path.join(output_dir, output_filename)
|
||||
|
||||
if self._need_link (objects, output_filename):
|
||||
if self._need_link(objects, output_filename):
|
||||
|
||||
# Figure out linker args based on type of target.
|
||||
if target_desc == CCompiler.EXECUTABLE:
|
||||
|
|
@ -213,20 +223,21 @@ class BCPPCompiler(CCompiler) :
|
|||
else:
|
||||
ld_args = self.ldflags_shared[:]
|
||||
|
||||
|
||||
# Create a temporary exports file for use by the linker
|
||||
if export_symbols is None:
|
||||
def_file = ''
|
||||
else:
|
||||
head, tail = os.path.split (output_filename)
|
||||
modname, ext = os.path.splitext (tail)
|
||||
temp_dir = os.path.dirname(objects[0]) # preserve tree structure
|
||||
def_file = os.path.join (temp_dir, '%s.def' % modname)
|
||||
head, tail = os.path.split(output_filename)
|
||||
modname, ext = os.path.splitext(tail)
|
||||
temp_dir = os.path.dirname(objects[0]) # preserve tree structure
|
||||
def_file = os.path.join(temp_dir, '%s.def' % modname)
|
||||
contents = ['EXPORTS']
|
||||
for sym in (export_symbols or []):
|
||||
contents.append(' %s=_%s' % (sym, sym))
|
||||
self.execute(write_file, (def_file, contents),
|
||||
"writing %s" % def_file)
|
||||
contents.append(' {}=_{}'.format(sym, sym))
|
||||
self.execute(
|
||||
write_file, (def_file, contents),
|
||||
'writing %s' % def_file,
|
||||
)
|
||||
|
||||
# Borland C++ has problems with '/' in paths
|
||||
objects2 = map(os.path.normpath, objects)
|
||||
|
|
@ -241,10 +252,9 @@ class BCPPCompiler(CCompiler) :
|
|||
else:
|
||||
objects.append(file)
|
||||
|
||||
|
||||
for l in library_dirs:
|
||||
ld_args.append("/L%s" % os.path.normpath(l))
|
||||
ld_args.append("/L.") # we sometimes use relative paths
|
||||
ld_args.append('/L%s' % os.path.normpath(l))
|
||||
ld_args.append('/L.') # we sometimes use relative paths
|
||||
|
||||
# list of object files
|
||||
ld_args.extend(objects)
|
||||
|
|
@ -260,7 +270,7 @@ class BCPPCompiler(CCompiler) :
|
|||
# them. Arghghh!. Apparently it works fine as coded...
|
||||
|
||||
# name of dll/exe file
|
||||
ld_args.extend([',',output_filename])
|
||||
ld_args.extend([',', output_filename])
|
||||
# no map file and start libraries
|
||||
ld_args.append(',,')
|
||||
|
||||
|
|
@ -276,36 +286,34 @@ class BCPPCompiler(CCompiler) :
|
|||
ld_args.append(libfile)
|
||||
|
||||
# some default libraries
|
||||
ld_args.append ('import32')
|
||||
ld_args.append ('cw32mt')
|
||||
ld_args.append('import32')
|
||||
ld_args.append('cw32mt')
|
||||
|
||||
# def file for export symbols
|
||||
ld_args.extend([',',def_file])
|
||||
ld_args.extend([',', def_file])
|
||||
# add resource files
|
||||
ld_args.append(',')
|
||||
ld_args.extend(resources)
|
||||
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
if extra_postargs:
|
||||
ld_args.extend(extra_postargs)
|
||||
|
||||
self.mkpath (os.path.dirname (output_filename))
|
||||
self.mkpath(os.path.dirname(output_filename))
|
||||
try:
|
||||
self.spawn ([self.linker] + ld_args)
|
||||
self.spawn([self.linker] + ld_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise LinkError(msg)
|
||||
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
# link ()
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
|
||||
|
||||
def find_library_file (self, dirs, lib, debug=0):
|
||||
def find_library_file(self, dirs, lib, debug=0):
|
||||
# List of effective library names to try, in order of preference:
|
||||
# xxx_bcpp.lib is better than xxx.lib
|
||||
# and xxx_d.lib is better than xxx.lib if debug is set
|
||||
|
|
@ -316,10 +324,10 @@ class BCPPCompiler(CCompiler) :
|
|||
# compiler they care about, since (almost?) every Windows compiler
|
||||
# seems to have a different format for static libraries.
|
||||
if debug:
|
||||
dlib = (lib + "_d")
|
||||
try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib)
|
||||
dlib = (lib + '_d')
|
||||
try_names = (dlib + '_bcpp', lib + '_bcpp', dlib, lib)
|
||||
else:
|
||||
try_names = (lib + "_bcpp", lib)
|
||||
try_names = (lib + '_bcpp', lib)
|
||||
|
||||
for dir in dirs:
|
||||
for name in try_names:
|
||||
|
|
@ -331,40 +339,51 @@ class BCPPCompiler(CCompiler) :
|
|||
return None
|
||||
|
||||
# overwrite the one from CCompiler to support rc and res-files
|
||||
def object_filenames (self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
if output_dir is None: output_dir = ''
|
||||
def object_filenames(
|
||||
self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir='',
|
||||
):
|
||||
if output_dir is None:
|
||||
output_dir = ''
|
||||
obj_names = []
|
||||
for src_name in source_filenames:
|
||||
# use normcase to make sure '.rc' is really '.rc' and not '.RC'
|
||||
(base, ext) = os.path.splitext (os.path.normcase(src_name))
|
||||
if ext not in (self.src_extensions + ['.rc','.res']):
|
||||
raise UnknownFileError("unknown file type '%s' (from '%s')" % \
|
||||
(ext, src_name))
|
||||
(base, ext) = os.path.splitext(os.path.normcase(src_name))
|
||||
if ext not in (self.src_extensions + ['.rc', '.res']):
|
||||
raise UnknownFileError(
|
||||
"unknown file type '%s' (from '%s')" %
|
||||
(ext, src_name),
|
||||
)
|
||||
if strip_dir:
|
||||
base = os.path.basename (base)
|
||||
base = os.path.basename(base)
|
||||
if ext == '.res':
|
||||
# these can go unchanged
|
||||
obj_names.append (os.path.join (output_dir, base + ext))
|
||||
obj_names.append(os.path.join(output_dir, base + ext))
|
||||
elif ext == '.rc':
|
||||
# these need to be compiled to .res-files
|
||||
obj_names.append (os.path.join (output_dir, base + '.res'))
|
||||
obj_names.append(os.path.join(output_dir, base + '.res'))
|
||||
else:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.obj_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.obj_extension,
|
||||
),
|
||||
)
|
||||
return obj_names
|
||||
|
||||
# object_filenames ()
|
||||
|
||||
def preprocess (self,
|
||||
source,
|
||||
output_file=None,
|
||||
macros=None,
|
||||
include_dirs=None,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None):
|
||||
def preprocess(
|
||||
self,
|
||||
source,
|
||||
output_file=None,
|
||||
macros=None,
|
||||
include_dirs=None,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
):
|
||||
|
||||
(_, macros, include_dirs) = \
|
||||
self._fix_compile_args(None, macros, include_dirs)
|
||||
|
|
|
|||
|
|
@ -2,15 +2,21 @@
|
|||
|
||||
Contains CCompiler, an abstract base class that defines the interface
|
||||
for the Distutils compiler abstraction model."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import sys, os, re
|
||||
from distutils.errors import *
|
||||
from distutils.spawn import spawn
|
||||
from distutils.file_util import move_file
|
||||
from distutils.dir_util import mkpath
|
||||
from distutils.dep_util import newer_group
|
||||
from distutils.util import split_quoted, execute
|
||||
from distutils import log
|
||||
from distutils.dep_util import newer_group
|
||||
from distutils.dir_util import mkpath
|
||||
from distutils.errors import *
|
||||
from distutils.file_util import move_file
|
||||
from distutils.spawn import spawn
|
||||
from distutils.util import execute
|
||||
from distutils.util import split_quoted
|
||||
|
||||
|
||||
class CCompiler:
|
||||
"""Abstract base class to define the interface that must be implemented
|
||||
|
|
@ -56,7 +62,6 @@ class CCompiler:
|
|||
# think this is useless without the ability to null out the
|
||||
# library search path anyways.
|
||||
|
||||
|
||||
# Subclasses that rely on the standard filename generation methods
|
||||
# implemented below should override these; see the comment near
|
||||
# those methods ('object_filenames()' et. al.) for details:
|
||||
|
|
@ -74,13 +79,14 @@ class CCompiler:
|
|||
# what language to use when mixing source types. For example, if some
|
||||
# extension has two files with ".c" extension, and one with ".cpp", it
|
||||
# is still linked as c++.
|
||||
language_map = {".c" : "c",
|
||||
".cc" : "c++",
|
||||
".cpp" : "c++",
|
||||
".cxx" : "c++",
|
||||
".m" : "objc",
|
||||
}
|
||||
language_order = ["c++", "objc", "c"]
|
||||
language_map = {
|
||||
'.c': 'c',
|
||||
'.cc': 'c++',
|
||||
'.cpp': 'c++',
|
||||
'.cxx': 'c++',
|
||||
'.m': 'objc',
|
||||
}
|
||||
language_order = ['c++', 'objc', 'c']
|
||||
|
||||
def __init__(self, verbose=0, dry_run=0, force=0):
|
||||
self.dry_run = dry_run
|
||||
|
|
@ -146,8 +152,10 @@ class CCompiler:
|
|||
|
||||
for key in kwargs:
|
||||
if key not in self.executables:
|
||||
raise ValueError("unknown executable '%s' for class %s" %
|
||||
(key, self.__class__.__name__))
|
||||
raise ValueError(
|
||||
"unknown executable '%s' for class %s" %
|
||||
(key, self.__class__.__name__),
|
||||
)
|
||||
self.set_executable(key, kwargs[key])
|
||||
|
||||
def set_executable(self, key, value):
|
||||
|
|
@ -170,14 +178,19 @@ class CCompiler:
|
|||
nothing if all definitions are OK, raise TypeError otherwise.
|
||||
"""
|
||||
for defn in definitions:
|
||||
if not (isinstance(defn, tuple) and
|
||||
(len(defn) in (1, 2) and
|
||||
(isinstance (defn[1], str) or defn[1] is None)) and
|
||||
isinstance (defn[0], str)):
|
||||
raise TypeError(("invalid macro definition '%s': " % defn) + \
|
||||
"must be tuple (string,), (string, string), or " + \
|
||||
"(string, None)")
|
||||
|
||||
if not (
|
||||
isinstance(defn, tuple) and
|
||||
(
|
||||
len(defn) in (1, 2) and
|
||||
(isinstance(defn[1], str) or defn[1] is None)
|
||||
) and
|
||||
isinstance(defn[0], str)
|
||||
):
|
||||
raise TypeError(
|
||||
("invalid macro definition '%s': " % defn) +
|
||||
'must be tuple (string,), (string, string), or ' +
|
||||
'(string, None)',
|
||||
)
|
||||
|
||||
# -- Bookkeeping methods -------------------------------------------
|
||||
|
||||
|
|
@ -190,7 +203,7 @@ class CCompiler:
|
|||
"""
|
||||
# Delete from the list of macro definitions/undefinitions if
|
||||
# already there (so that this one will take precedence).
|
||||
i = self._find_macro (name)
|
||||
i = self._find_macro(name)
|
||||
if i is not None:
|
||||
del self.macros[i]
|
||||
|
||||
|
|
@ -207,7 +220,7 @@ class CCompiler:
|
|||
"""
|
||||
# Delete from the list of macro definitions/undefinitions if
|
||||
# already there (so that this one will take precedence).
|
||||
i = self._find_macro (name)
|
||||
i = self._find_macro(name)
|
||||
if i is not None:
|
||||
del self.macros[i]
|
||||
|
||||
|
|
@ -301,14 +314,15 @@ class CCompiler:
|
|||
"""
|
||||
self.objects = objects[:]
|
||||
|
||||
|
||||
# -- Private utility methods --------------------------------------
|
||||
# (here for the convenience of subclasses)
|
||||
|
||||
# Helper method to prep compiler in subclass compile() methods
|
||||
|
||||
def _setup_compile(self, outdir, macros, incdirs, sources, depends,
|
||||
extra):
|
||||
def _setup_compile(
|
||||
self, outdir, macros, incdirs, sources, depends,
|
||||
extra,
|
||||
):
|
||||
"""Process arguments and decide which source files to compile."""
|
||||
if outdir is None:
|
||||
outdir = self.output_dir
|
||||
|
|
@ -328,14 +342,17 @@ class CCompiler:
|
|||
incdirs = list(incdirs) + (self.include_dirs or [])
|
||||
else:
|
||||
raise TypeError(
|
||||
"'include_dirs' (if supplied) must be a list of strings")
|
||||
"'include_dirs' (if supplied) must be a list of strings",
|
||||
)
|
||||
|
||||
if extra is None:
|
||||
extra = []
|
||||
|
||||
# Get the list of expected output (object) files
|
||||
objects = self.object_filenames(sources, strip_dir=0,
|
||||
output_dir=outdir)
|
||||
objects = self.object_filenames(
|
||||
sources, strip_dir=0,
|
||||
output_dir=outdir,
|
||||
)
|
||||
assert len(objects) == len(sources)
|
||||
|
||||
pp_opts = gen_preprocess_options(macros, incdirs)
|
||||
|
|
@ -387,7 +404,8 @@ class CCompiler:
|
|||
include_dirs = list(include_dirs) + (self.include_dirs or [])
|
||||
else:
|
||||
raise TypeError(
|
||||
"'include_dirs' (if supplied) must be a list of strings")
|
||||
"'include_dirs' (if supplied) must be a list of strings",
|
||||
)
|
||||
|
||||
return output_dir, macros, include_dirs
|
||||
|
||||
|
|
@ -434,27 +452,33 @@ class CCompiler:
|
|||
if libraries is None:
|
||||
libraries = self.libraries
|
||||
elif isinstance(libraries, (list, tuple)):
|
||||
libraries = list (libraries) + (self.libraries or [])
|
||||
libraries = list(libraries) + (self.libraries or [])
|
||||
else:
|
||||
raise TypeError(
|
||||
"'libraries' (if supplied) must be a list of strings")
|
||||
"'libraries' (if supplied) must be a list of strings",
|
||||
)
|
||||
|
||||
if library_dirs is None:
|
||||
library_dirs = self.library_dirs
|
||||
elif isinstance(library_dirs, (list, tuple)):
|
||||
library_dirs = list (library_dirs) + (self.library_dirs or [])
|
||||
library_dirs = list(library_dirs) + (self.library_dirs or [])
|
||||
else:
|
||||
raise TypeError(
|
||||
"'library_dirs' (if supplied) must be a list of strings")
|
||||
"'library_dirs' (if supplied) must be a list of strings",
|
||||
)
|
||||
|
||||
if runtime_library_dirs is None:
|
||||
runtime_library_dirs = self.runtime_library_dirs
|
||||
elif isinstance(runtime_library_dirs, (list, tuple)):
|
||||
runtime_library_dirs = (list(runtime_library_dirs) +
|
||||
(self.runtime_library_dirs or []))
|
||||
runtime_library_dirs = (
|
||||
list(runtime_library_dirs) +
|
||||
(self.runtime_library_dirs or [])
|
||||
)
|
||||
else:
|
||||
raise TypeError("'runtime_library_dirs' (if supplied) "
|
||||
"must be a list of strings")
|
||||
raise TypeError(
|
||||
"'runtime_library_dirs' (if supplied) "
|
||||
'must be a list of strings',
|
||||
)
|
||||
|
||||
return (libraries, library_dirs, runtime_library_dirs)
|
||||
|
||||
|
|
@ -466,9 +490,9 @@ class CCompiler:
|
|||
return True
|
||||
else:
|
||||
if self.dry_run:
|
||||
newer = newer_group (objects, output_file, missing='newer')
|
||||
newer = newer_group(objects, output_file, missing='newer')
|
||||
else:
|
||||
newer = newer_group (objects, output_file)
|
||||
newer = newer_group(objects, output_file)
|
||||
return newer
|
||||
|
||||
def detect_language(self, sources):
|
||||
|
|
@ -491,12 +515,13 @@ class CCompiler:
|
|||
pass
|
||||
return lang
|
||||
|
||||
|
||||
# -- Worker methods ------------------------------------------------
|
||||
# (must be implemented by subclasses)
|
||||
|
||||
def preprocess(self, source, output_file=None, macros=None,
|
||||
include_dirs=None, extra_preargs=None, extra_postargs=None):
|
||||
def preprocess(
|
||||
self, source, output_file=None, macros=None,
|
||||
include_dirs=None, extra_preargs=None, extra_postargs=None,
|
||||
):
|
||||
"""Preprocess a single C/C++ source file, named in 'source'.
|
||||
Output will be written to file named 'output_file', or stdout if
|
||||
'output_file' not supplied. 'macros' is a list of macro
|
||||
|
|
@ -508,9 +533,11 @@ class CCompiler:
|
|||
"""
|
||||
pass
|
||||
|
||||
def compile(self, sources, output_dir=None, macros=None,
|
||||
include_dirs=None, debug=0, extra_preargs=None,
|
||||
extra_postargs=None, depends=None):
|
||||
def compile(
|
||||
self, sources, output_dir=None, macros=None,
|
||||
include_dirs=None, debug=0, extra_preargs=None,
|
||||
extra_postargs=None, depends=None,
|
||||
):
|
||||
"""Compile one or more source files.
|
||||
|
||||
'sources' must be a list of filenames, most likely C/C++
|
||||
|
|
@ -562,8 +589,10 @@ class CCompiler:
|
|||
# A concrete compiler class can either override this method
|
||||
# entirely or implement _compile().
|
||||
macros, objects, extra_postargs, pp_opts, build = \
|
||||
self._setup_compile(output_dir, macros, include_dirs, sources,
|
||||
depends, extra_postargs)
|
||||
self._setup_compile(
|
||||
output_dir, macros, include_dirs, sources,
|
||||
depends, extra_postargs,
|
||||
)
|
||||
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
|
||||
|
||||
for obj in objects:
|
||||
|
|
@ -582,8 +611,10 @@ class CCompiler:
|
|||
# should implement _compile().
|
||||
pass
|
||||
|
||||
def create_static_lib(self, objects, output_libname, output_dir=None,
|
||||
debug=0, target_lang=None):
|
||||
def create_static_lib(
|
||||
self, objects, output_libname, output_dir=None,
|
||||
debug=0, target_lang=None,
|
||||
):
|
||||
"""Link a bunch of stuff together to create a static library file.
|
||||
The "bunch of stuff" consists of the list of object files supplied
|
||||
as 'objects', the extra object files supplied to
|
||||
|
|
@ -608,26 +639,27 @@ class CCompiler:
|
|||
"""
|
||||
pass
|
||||
|
||||
|
||||
# values for target_desc parameter in link()
|
||||
SHARED_OBJECT = "shared_object"
|
||||
SHARED_LIBRARY = "shared_library"
|
||||
EXECUTABLE = "executable"
|
||||
SHARED_OBJECT = 'shared_object'
|
||||
SHARED_LIBRARY = 'shared_library'
|
||||
EXECUTABLE = 'executable'
|
||||
|
||||
def link(self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
def link(
|
||||
self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
"""Link a bunch of stuff together to create an executable or
|
||||
shared library file.
|
||||
|
||||
|
|
@ -673,66 +705,74 @@ class CCompiler:
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
# Old 'link_*()' methods, rewritten to use the new 'link()' method.
|
||||
|
||||
def link_shared_lib(self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
self.link(CCompiler.SHARED_LIBRARY, objects,
|
||||
self.library_filename(output_libname, lib_type='shared'),
|
||||
output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug,
|
||||
extra_preargs, extra_postargs, build_temp, target_lang)
|
||||
def link_shared_lib(
|
||||
self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
self.link(
|
||||
CCompiler.SHARED_LIBRARY, objects,
|
||||
self.library_filename(output_libname, lib_type='shared'),
|
||||
output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug,
|
||||
extra_preargs, extra_postargs, build_temp, target_lang,
|
||||
)
|
||||
|
||||
def link_shared_object(
|
||||
self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
self.link(
|
||||
CCompiler.SHARED_OBJECT, objects,
|
||||
output_filename, output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug,
|
||||
extra_preargs, extra_postargs, build_temp, target_lang,
|
||||
)
|
||||
|
||||
def link_shared_object(self,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
self.link(CCompiler.SHARED_OBJECT, objects,
|
||||
output_filename, output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug,
|
||||
extra_preargs, extra_postargs, build_temp, target_lang)
|
||||
|
||||
|
||||
def link_executable(self,
|
||||
objects,
|
||||
output_progname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
target_lang=None):
|
||||
self.link(CCompiler.EXECUTABLE, objects,
|
||||
self.executable_filename(output_progname), output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs, None,
|
||||
debug, extra_preargs, extra_postargs, None, target_lang)
|
||||
|
||||
def link_executable(
|
||||
self,
|
||||
objects,
|
||||
output_progname,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
target_lang=None,
|
||||
):
|
||||
self.link(
|
||||
CCompiler.EXECUTABLE, objects,
|
||||
self.executable_filename(output_progname), output_dir,
|
||||
libraries, library_dirs, runtime_library_dirs, None,
|
||||
debug, extra_preargs, extra_postargs, None, target_lang,
|
||||
)
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
# These are all used by the 'gen_lib_options() function; there is
|
||||
|
|
@ -757,8 +797,10 @@ class CCompiler:
|
|||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def has_function(self, funcname, includes=None, include_dirs=None,
|
||||
libraries=None, library_dirs=None):
|
||||
def has_function(
|
||||
self, funcname, includes=None, include_dirs=None,
|
||||
libraries=None, library_dirs=None,
|
||||
):
|
||||
"""Return a boolean indicating whether funcname is supported on
|
||||
the current platform. The optional arguments can be used to
|
||||
augment the compilation environment.
|
||||
|
|
@ -775,17 +817,19 @@ class CCompiler:
|
|||
libraries = []
|
||||
if library_dirs is None:
|
||||
library_dirs = []
|
||||
fd, fname = tempfile.mkstemp(".c", funcname, text=True)
|
||||
f = os.fdopen(fd, "w")
|
||||
fd, fname = tempfile.mkstemp('.c', funcname, text=True)
|
||||
f = os.fdopen(fd, 'w')
|
||||
try:
|
||||
for incl in includes:
|
||||
f.write("""#include "%s"\n""" % incl)
|
||||
f.write("""\
|
||||
f.write(
|
||||
"""\
|
||||
int main (int argc, char **argv) {
|
||||
%s();
|
||||
return 0;
|
||||
}
|
||||
""" % funcname)
|
||||
""" % funcname,
|
||||
)
|
||||
finally:
|
||||
f.close()
|
||||
try:
|
||||
|
|
@ -796,19 +840,21 @@ int main (int argc, char **argv) {
|
|||
os.remove(fname)
|
||||
|
||||
try:
|
||||
self.link_executable(objects, "a.out",
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs)
|
||||
self.link_executable(
|
||||
objects, 'a.out',
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs,
|
||||
)
|
||||
except (LinkError, TypeError):
|
||||
return False
|
||||
else:
|
||||
os.remove("a.out")
|
||||
os.remove('a.out')
|
||||
finally:
|
||||
for fn in objects:
|
||||
os.remove(fn)
|
||||
return True
|
||||
|
||||
def find_library_file (self, dirs, lib, debug=0):
|
||||
def find_library_file(self, dirs, lib, debug=0):
|
||||
"""Search the specified list of directories for a static or shared
|
||||
library file 'lib' and return the full path to that file. If
|
||||
'debug' true, look for a debugging version (if that makes sense on
|
||||
|
|
@ -857,15 +903,20 @@ int main (int argc, char **argv) {
|
|||
obj_names = []
|
||||
for src_name in source_filenames:
|
||||
base, ext = os.path.splitext(src_name)
|
||||
base = os.path.splitdrive(base)[1] # Chop off the drive
|
||||
base = os.path.splitdrive(base)[1] # Chop off the drive
|
||||
base = base[os.path.isabs(base):] # If abs, chop off leading /
|
||||
if ext not in self.src_extensions:
|
||||
raise UnknownFileError(
|
||||
"unknown file type '%s' (from '%s')" % (ext, src_name))
|
||||
"unknown file type '{}' (from '{}')".format(ext, src_name),
|
||||
)
|
||||
if strip_dir:
|
||||
base = os.path.basename(base)
|
||||
obj_names.append(os.path.join(output_dir,
|
||||
base + self.obj_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.obj_extension,
|
||||
),
|
||||
)
|
||||
return obj_names
|
||||
|
||||
def shared_object_filename(self, basename, strip_dir=0, output_dir=''):
|
||||
|
|
@ -880,14 +931,17 @@ int main (int argc, char **argv) {
|
|||
basename = os.path.basename(basename)
|
||||
return os.path.join(output_dir, basename + (self.exe_extension or ''))
|
||||
|
||||
def library_filename(self, libname, lib_type='static', # or 'shared'
|
||||
strip_dir=0, output_dir=''):
|
||||
def library_filename(
|
||||
self, libname, lib_type='static', # or 'shared'
|
||||
strip_dir=0, output_dir='',
|
||||
):
|
||||
assert output_dir is not None
|
||||
if lib_type not in ("static", "shared", "dylib", "xcode_stub"):
|
||||
if lib_type not in ('static', 'shared', 'dylib', 'xcode_stub'):
|
||||
raise ValueError(
|
||||
"'lib_type' must be \"static\", \"shared\", \"dylib\", or \"xcode_stub\"")
|
||||
fmt = getattr(self, lib_type + "_lib_format")
|
||||
ext = getattr(self, lib_type + "_lib_extension")
|
||||
"'lib_type' must be \"static\", \"shared\", \"dylib\", or \"xcode_stub\"",
|
||||
)
|
||||
fmt = getattr(self, lib_type + '_lib_format')
|
||||
ext = getattr(self, lib_type + '_lib_extension')
|
||||
|
||||
dir, base = os.path.split(libname)
|
||||
filename = fmt % (base, ext)
|
||||
|
|
@ -896,7 +950,6 @@ int main (int argc, char **argv) {
|
|||
|
||||
return os.path.join(output_dir, dir, filename)
|
||||
|
||||
|
||||
# -- Utility methods -----------------------------------------------
|
||||
|
||||
def announce(self, msg, level=1):
|
||||
|
|
@ -908,7 +961,7 @@ int main (int argc, char **argv) {
|
|||
print(msg)
|
||||
|
||||
def warn(self, msg):
|
||||
sys.stderr.write("warning: %s\n" % msg)
|
||||
sys.stderr.write('warning: %s\n' % msg)
|
||||
|
||||
def execute(self, func, args, msg=None, level=1):
|
||||
execute(func, args, msg, self.dry_run)
|
||||
|
|
@ -919,7 +972,7 @@ int main (int argc, char **argv) {
|
|||
def move_file(self, src, dst):
|
||||
return move_file(src, dst, dry_run=self.dry_run)
|
||||
|
||||
def mkpath (self, name, mode=0o777):
|
||||
def mkpath(self, name, mode=0o777):
|
||||
mkpath(name, mode, dry_run=self.dry_run)
|
||||
|
||||
|
||||
|
|
@ -939,7 +992,8 @@ _default_compilers = (
|
|||
('posix', 'unix'),
|
||||
('nt', 'msvc'),
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_default_compiler(osname=None, platform=None):
|
||||
"""Determine the default compiler to use for the given platform.
|
||||
|
|
@ -962,20 +1016,32 @@ def get_default_compiler(osname=None, platform=None):
|
|||
# Default to Unix compiler
|
||||
return 'unix'
|
||||
|
||||
|
||||
# Map compiler types to (module_name, class_name) pairs -- ie. where to
|
||||
# find the code that implements an interface to this compiler. (The module
|
||||
# is assumed to be in the 'distutils' package.)
|
||||
compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler',
|
||||
"standard UNIX-style compiler"),
|
||||
'msvc': ('_msvccompiler', 'MSVCCompiler',
|
||||
"Microsoft Visual C++"),
|
||||
'cygwin': ('cygwinccompiler', 'CygwinCCompiler',
|
||||
"Cygwin port of GNU C Compiler for Win32"),
|
||||
'mingw32': ('cygwinccompiler', 'Mingw32CCompiler',
|
||||
"Mingw32 port of GNU C Compiler for Win32"),
|
||||
'bcpp': ('bcppcompiler', 'BCPPCompiler',
|
||||
"Borland C++ Compiler"),
|
||||
}
|
||||
compiler_class = {'unix': (
|
||||
'unixccompiler', 'UnixCCompiler',
|
||||
'standard UNIX-style compiler',
|
||||
),
|
||||
'msvc': (
|
||||
'_msvccompiler', 'MSVCCompiler',
|
||||
'Microsoft Visual C++',
|
||||
),
|
||||
'cygwin': (
|
||||
'cygwinccompiler', 'CygwinCCompiler',
|
||||
'Cygwin port of GNU C Compiler for Win32',
|
||||
),
|
||||
'mingw32': (
|
||||
'cygwinccompiler', 'Mingw32CCompiler',
|
||||
'Mingw32 port of GNU C Compiler for Win32',
|
||||
),
|
||||
'bcpp': (
|
||||
'bcppcompiler', 'BCPPCompiler',
|
||||
'Borland C++ Compiler',
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def show_compilers():
|
||||
"""Print list of available compilers (used by the "--help-compiler"
|
||||
|
|
@ -987,11 +1053,13 @@ def show_compilers():
|
|||
from distutils.fancy_getopt import FancyGetopt
|
||||
compilers = []
|
||||
for compiler in compiler_class.keys():
|
||||
compilers.append(("compiler="+compiler, None,
|
||||
compiler_class[compiler][2]))
|
||||
compilers.append((
|
||||
'compiler=' + compiler, None,
|
||||
compiler_class[compiler][2],
|
||||
))
|
||||
compilers.sort()
|
||||
pretty_printer = FancyGetopt(compilers)
|
||||
pretty_printer.print_help("List of available compilers:")
|
||||
pretty_printer.print_help('List of available compilers:')
|
||||
|
||||
|
||||
def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
|
||||
|
|
@ -1020,18 +1088,20 @@ def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
|
|||
raise DistutilsPlatformError(msg)
|
||||
|
||||
try:
|
||||
module_name = "distutils." + module_name
|
||||
__import__ (module_name)
|
||||
module_name = 'distutils.' + module_name
|
||||
__import__(module_name)
|
||||
module = sys.modules[module_name]
|
||||
klass = vars(module)[class_name]
|
||||
except ImportError:
|
||||
raise DistutilsModuleError(
|
||||
"can't compile C/C++ code: unable to load module '%s'" % \
|
||||
module_name)
|
||||
"can't compile C/C++ code: unable to load module '%s'" %
|
||||
module_name,
|
||||
)
|
||||
except KeyError:
|
||||
raise DistutilsModuleError(
|
||||
"can't compile C/C++ code: unable to find class '%s' "
|
||||
"in module '%s'" % (class_name, module_name))
|
||||
"can't compile C/C++ code: unable to find class '%s' "
|
||||
"in module '%s'" % (class_name, module_name),
|
||||
)
|
||||
|
||||
# XXX The None is necessary to preserve backwards compatibility
|
||||
# with classes that expect verbose to be the first positional
|
||||
|
|
@ -1064,27 +1134,28 @@ def gen_preprocess_options(macros, include_dirs):
|
|||
for macro in macros:
|
||||
if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2):
|
||||
raise TypeError(
|
||||
"bad macro definition '%s': "
|
||||
"each element of 'macros' list must be a 1- or 2-tuple"
|
||||
% macro)
|
||||
"bad macro definition '%s': "
|
||||
"each element of 'macros' list must be a 1- or 2-tuple"
|
||||
% macro,
|
||||
)
|
||||
|
||||
if len(macro) == 1: # undefine this macro
|
||||
pp_opts.append("-U%s" % macro[0])
|
||||
pp_opts.append('-U%s' % macro[0])
|
||||
elif len(macro) == 2:
|
||||
if macro[1] is None: # define with no explicit value
|
||||
pp_opts.append("-D%s" % macro[0])
|
||||
pp_opts.append('-D%s' % macro[0])
|
||||
else:
|
||||
# XXX *don't* need to be clever about quoting the
|
||||
# macro value here, because we're going to avoid the
|
||||
# shell at all costs when we spawn the command!
|
||||
pp_opts.append("-D%s=%s" % macro)
|
||||
pp_opts.append('-D%s=%s' % macro)
|
||||
|
||||
for dir in include_dirs:
|
||||
pp_opts.append("-I%s" % dir)
|
||||
pp_opts.append('-I%s' % dir)
|
||||
return pp_opts
|
||||
|
||||
|
||||
def gen_lib_options (compiler, library_dirs, runtime_library_dirs, libraries):
|
||||
def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
|
||||
"""Generate linker options for searching library directories and
|
||||
linking with specific libraries. 'libraries' and 'library_dirs' are,
|
||||
respectively, lists of library names (not filenames!) and search
|
||||
|
|
@ -1116,8 +1187,10 @@ def gen_lib_options (compiler, library_dirs, runtime_library_dirs, libraries):
|
|||
if lib_file:
|
||||
lib_opts.append(lib_file)
|
||||
else:
|
||||
compiler.warn("no library file corresponding to "
|
||||
"'%s' found (skipping)" % lib)
|
||||
compiler.warn(
|
||||
'no library file corresponding to '
|
||||
"'%s' found (skipping)" % lib,
|
||||
)
|
||||
else:
|
||||
lib_opts.append(compiler.library_option (lib))
|
||||
lib_opts.append(compiler.library_option(lib))
|
||||
return lib_opts
|
||||
|
|
|
|||
|
|
@ -3,11 +3,20 @@
|
|||
Provides the Command class, the base class for the command classes
|
||||
in the distutils.command package.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys, os, re
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils import util, dir_util, file_util, archive_util, dep_util
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from distutils import archive_util
|
||||
from distutils import dep_util
|
||||
from distutils import dir_util
|
||||
from distutils import file_util
|
||||
from distutils import log
|
||||
from distutils import util
|
||||
from distutils.errors import DistutilsOptionError
|
||||
|
||||
|
||||
class Command:
|
||||
"""Abstract base class for defining command classes, the "worker bees"
|
||||
|
|
@ -41,7 +50,6 @@ class Command:
|
|||
# defined. The canonical example is the "install" command.
|
||||
sub_commands = []
|
||||
|
||||
|
||||
# -- Creation/initialization methods -------------------------------
|
||||
|
||||
def __init__(self, dist):
|
||||
|
|
@ -54,9 +62,9 @@ class Command:
|
|||
from distutils.dist import Distribution
|
||||
|
||||
if not isinstance(dist, Distribution):
|
||||
raise TypeError("dist must be a Distribution instance")
|
||||
raise TypeError('dist must be a Distribution instance')
|
||||
if self.__class__ is Command:
|
||||
raise RuntimeError("Command is an abstract class")
|
||||
raise RuntimeError('Command is an abstract class')
|
||||
|
||||
self.distribution = dist
|
||||
self.initialize_options()
|
||||
|
|
@ -94,7 +102,7 @@ class Command:
|
|||
# XXX A more explicit way to customize dry_run would be better.
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'dry_run':
|
||||
myval = getattr(self, "_" + attr)
|
||||
myval = getattr(self, '_' + attr)
|
||||
if myval is None:
|
||||
return getattr(self.distribution, attr)
|
||||
else:
|
||||
|
|
@ -130,8 +138,10 @@ class Command:
|
|||
|
||||
This method must be implemented by all command classes.
|
||||
"""
|
||||
raise RuntimeError("abstract method -- subclass %s must override"
|
||||
% self.__class__)
|
||||
raise RuntimeError(
|
||||
'abstract method -- subclass %s must override'
|
||||
% self.__class__,
|
||||
)
|
||||
|
||||
def finalize_options(self):
|
||||
"""Set final values for all the options that this command supports.
|
||||
|
|
@ -144,23 +154,26 @@ class Command:
|
|||
|
||||
This method must be implemented by all command classes.
|
||||
"""
|
||||
raise RuntimeError("abstract method -- subclass %s must override"
|
||||
% self.__class__)
|
||||
raise RuntimeError(
|
||||
'abstract method -- subclass %s must override'
|
||||
% self.__class__,
|
||||
)
|
||||
|
||||
|
||||
def dump_options(self, header=None, indent=""):
|
||||
def dump_options(self, header=None, indent=''):
|
||||
from distutils.fancy_getopt import longopt_xlate
|
||||
if header is None:
|
||||
header = "command options for '%s':" % self.get_command_name()
|
||||
self.announce(indent + header, level=log.INFO)
|
||||
indent = indent + " "
|
||||
indent = indent + ' '
|
||||
for (option, _, _) in self.user_options:
|
||||
option = option.translate(longopt_xlate)
|
||||
if option[-1] == "=":
|
||||
if option[-1] == '=':
|
||||
option = option[:-1]
|
||||
value = getattr(self, option)
|
||||
self.announce(indent + "%s = %s" % (option, value),
|
||||
level=log.INFO)
|
||||
self.announce(
|
||||
indent + '{} = {}'.format(option, value),
|
||||
level=log.INFO,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
"""A command's raison d'etre: carry out the action it exists to
|
||||
|
|
@ -172,8 +185,10 @@ class Command:
|
|||
|
||||
This method must be implemented by all command classes.
|
||||
"""
|
||||
raise RuntimeError("abstract method -- subclass %s must override"
|
||||
% self.__class__)
|
||||
raise RuntimeError(
|
||||
'abstract method -- subclass %s must override'
|
||||
% self.__class__,
|
||||
)
|
||||
|
||||
def announce(self, msg, level=1):
|
||||
"""If the current verbosity level is of greater than or equal to
|
||||
|
|
@ -190,7 +205,6 @@ class Command:
|
|||
print(msg)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
# -- Option validation methods -------------------------------------
|
||||
# (these are very handy in writing the 'finalize_options()' method)
|
||||
#
|
||||
|
|
@ -210,15 +224,17 @@ class Command:
|
|||
setattr(self, option, default)
|
||||
return default
|
||||
elif not isinstance(val, str):
|
||||
raise DistutilsOptionError("'%s' must be a %s (got `%s`)"
|
||||
% (option, what, val))
|
||||
raise DistutilsOptionError(
|
||||
"'%s' must be a %s (got `%s`)"
|
||||
% (option, what, val),
|
||||
)
|
||||
return val
|
||||
|
||||
def ensure_string(self, option, default=None):
|
||||
"""Ensure that 'option' is a string; if not defined, set it to
|
||||
'default'.
|
||||
"""
|
||||
self._ensure_stringlike(option, "string", default)
|
||||
self._ensure_stringlike(option, 'string', default)
|
||||
|
||||
def ensure_string_list(self, option):
|
||||
r"""Ensure that 'option' is a list of strings. If 'option' is
|
||||
|
|
@ -238,11 +254,14 @@ class Command:
|
|||
ok = False
|
||||
if not ok:
|
||||
raise DistutilsOptionError(
|
||||
"'%s' must be a list of strings (got %r)"
|
||||
% (option, val))
|
||||
"'%s' must be a list of strings (got %r)"
|
||||
% (option, val),
|
||||
)
|
||||
|
||||
def _ensure_tested_string(self, option, tester, what, error_fmt,
|
||||
default=None):
|
||||
def _ensure_tested_string(
|
||||
self, option, tester, what, error_fmt,
|
||||
default=None,
|
||||
):
|
||||
val = self._ensure_stringlike(option, what, default)
|
||||
if val is not None and not tester(val):
|
||||
raise DistutilsOptionError(("error in '%s' option: " + error_fmt)
|
||||
|
|
@ -250,15 +269,18 @@ class Command:
|
|||
|
||||
def ensure_filename(self, option):
|
||||
"""Ensure that 'option' is the name of an existing file."""
|
||||
self._ensure_tested_string(option, os.path.isfile,
|
||||
"filename",
|
||||
"'%s' does not exist or is not a file")
|
||||
self._ensure_tested_string(
|
||||
option, os.path.isfile,
|
||||
'filename',
|
||||
"'%s' does not exist or is not a file",
|
||||
)
|
||||
|
||||
def ensure_dirname(self, option):
|
||||
self._ensure_tested_string(option, os.path.isdir,
|
||||
"directory name",
|
||||
"'%s' does not exist or is not a directory")
|
||||
|
||||
self._ensure_tested_string(
|
||||
option, os.path.isdir,
|
||||
'directory name',
|
||||
"'%s' does not exist or is not a directory",
|
||||
)
|
||||
|
||||
# -- Convenience methods for commands ------------------------------
|
||||
|
||||
|
|
@ -302,8 +324,10 @@ class Command:
|
|||
# XXX rename to 'get_reinitialized_command()'? (should do the
|
||||
# same in dist.py, if so)
|
||||
def reinitialize_command(self, command, reinit_subcommands=0):
|
||||
return self.distribution.reinitialize_command(command,
|
||||
reinit_subcommands)
|
||||
return self.distribution.reinitialize_command(
|
||||
command,
|
||||
reinit_subcommands,
|
||||
)
|
||||
|
||||
def run_command(self, command):
|
||||
"""Run some other command: uses the 'run_command()' method of
|
||||
|
|
@ -325,11 +349,10 @@ class Command:
|
|||
commands.append(cmd_name)
|
||||
return commands
|
||||
|
||||
|
||||
# -- External world manipulation -----------------------------------
|
||||
|
||||
def warn(self, msg):
|
||||
log.warn("warning: %s: %s\n", self.get_command_name(), msg)
|
||||
log.warn('warning: %s: %s\n', self.get_command_name(), msg)
|
||||
|
||||
def execute(self, func, args, msg=None, level=1):
|
||||
util.execute(func, args, msg, dry_run=self.dry_run)
|
||||
|
|
@ -337,25 +360,33 @@ class Command:
|
|||
def mkpath(self, name, mode=0o777):
|
||||
dir_util.mkpath(name, mode, dry_run=self.dry_run)
|
||||
|
||||
def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1,
|
||||
link=None, level=1):
|
||||
def copy_file(
|
||||
self, infile, outfile, preserve_mode=1, preserve_times=1,
|
||||
link=None, level=1,
|
||||
):
|
||||
"""Copy a file respecting verbose, dry-run and force flags. (The
|
||||
former two default to whatever is in the Distribution object, and
|
||||
the latter defaults to false for commands that don't define it.)"""
|
||||
return file_util.copy_file(infile, outfile, preserve_mode,
|
||||
preserve_times, not self.force, link,
|
||||
dry_run=self.dry_run)
|
||||
return file_util.copy_file(
|
||||
infile, outfile, preserve_mode,
|
||||
preserve_times, not self.force, link,
|
||||
dry_run=self.dry_run,
|
||||
)
|
||||
|
||||
def copy_tree(self, infile, outfile, preserve_mode=1, preserve_times=1,
|
||||
preserve_symlinks=0, level=1):
|
||||
def copy_tree(
|
||||
self, infile, outfile, preserve_mode=1, preserve_times=1,
|
||||
preserve_symlinks=0, level=1,
|
||||
):
|
||||
"""Copy an entire directory tree respecting verbose, dry-run,
|
||||
and force flags.
|
||||
"""
|
||||
return dir_util.copy_tree(infile, outfile, preserve_mode,
|
||||
preserve_times, preserve_symlinks,
|
||||
not self.force, dry_run=self.dry_run)
|
||||
return dir_util.copy_tree(
|
||||
infile, outfile, preserve_mode,
|
||||
preserve_times, preserve_symlinks,
|
||||
not self.force, dry_run=self.dry_run,
|
||||
)
|
||||
|
||||
def move_file (self, src, dst, level=1):
|
||||
def move_file(self, src, dst, level=1):
|
||||
"""Move a file respecting dry-run flag."""
|
||||
return file_util.move_file(src, dst, dry_run=self.dry_run)
|
||||
|
||||
|
|
@ -364,14 +395,20 @@ class Command:
|
|||
from distutils.spawn import spawn
|
||||
spawn(cmd, search_path, dry_run=self.dry_run)
|
||||
|
||||
def make_archive(self, base_name, format, root_dir=None, base_dir=None,
|
||||
owner=None, group=None):
|
||||
return archive_util.make_archive(base_name, format, root_dir, base_dir,
|
||||
dry_run=self.dry_run,
|
||||
owner=owner, group=group)
|
||||
def make_archive(
|
||||
self, base_name, format, root_dir=None, base_dir=None,
|
||||
owner=None, group=None,
|
||||
):
|
||||
return archive_util.make_archive(
|
||||
base_name, format, root_dir, base_dir,
|
||||
dry_run=self.dry_run,
|
||||
owner=owner, group=group,
|
||||
)
|
||||
|
||||
def make_file(self, infiles, outfile, func, args,
|
||||
exec_msg=None, skip_msg=None, level=1):
|
||||
def make_file(
|
||||
self, infiles, outfile, func, args,
|
||||
exec_msg=None, skip_msg=None, level=1,
|
||||
):
|
||||
"""Special case of 'execute()' for operations that process one or
|
||||
more input files and generate one output file. Works just like
|
||||
'execute()', except the operation is skipped and a different
|
||||
|
|
@ -381,17 +418,18 @@ class Command:
|
|||
timestamp checks.
|
||||
"""
|
||||
if skip_msg is None:
|
||||
skip_msg = "skipping %s (inputs unchanged)" % outfile
|
||||
skip_msg = 'skipping %s (inputs unchanged)' % outfile
|
||||
|
||||
# Allow 'infiles' to be a single string
|
||||
if isinstance(infiles, str):
|
||||
infiles = (infiles,)
|
||||
elif not isinstance(infiles, (list, tuple)):
|
||||
raise TypeError(
|
||||
"'infiles' must be a string, or a list or tuple of strings")
|
||||
"'infiles' must be a string, or a list or tuple of strings",
|
||||
)
|
||||
|
||||
if exec_msg is None:
|
||||
exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles))
|
||||
exec_msg = 'generating {} from {}'.format(outfile, ', '.join(infiles))
|
||||
|
||||
# If 'outfile' must be regenerated (either because it doesn't
|
||||
# exist, is out-of-date, or the 'force' flag is true) then
|
||||
|
|
|
|||
|
|
@ -2,30 +2,32 @@
|
|||
|
||||
Package containing implementation of all the standard Distutils
|
||||
commands."""
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ['build',
|
||||
'build_py',
|
||||
'build_ext',
|
||||
'build_clib',
|
||||
'build_scripts',
|
||||
'clean',
|
||||
'install',
|
||||
'install_lib',
|
||||
'install_headers',
|
||||
'install_scripts',
|
||||
'install_data',
|
||||
'sdist',
|
||||
'register',
|
||||
'bdist',
|
||||
'bdist_dumb',
|
||||
'bdist_rpm',
|
||||
'bdist_wininst',
|
||||
'check',
|
||||
'upload',
|
||||
# These two are reserved for future use:
|
||||
#'bdist_sdux',
|
||||
#'bdist_pkgtool',
|
||||
# Note:
|
||||
# bdist_packager is not included because it only provides
|
||||
# an abstract base class
|
||||
]
|
||||
__all__ = [
|
||||
'build',
|
||||
'build_py',
|
||||
'build_ext',
|
||||
'build_clib',
|
||||
'build_scripts',
|
||||
'clean',
|
||||
'install',
|
||||
'install_lib',
|
||||
'install_headers',
|
||||
'install_scripts',
|
||||
'install_data',
|
||||
'sdist',
|
||||
'register',
|
||||
'bdist',
|
||||
'bdist_dumb',
|
||||
'bdist_rpm',
|
||||
'bdist_wininst',
|
||||
'check',
|
||||
'upload',
|
||||
# These two are reserved for future use:
|
||||
#'bdist_sdux',
|
||||
#'bdist_pkgtool',
|
||||
# Note:
|
||||
# bdist_packager is not included because it only provides
|
||||
# an abstract base class
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
Implements the Distutils 'bdist' command (create a built [binary]
|
||||
distribution)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
from distutils.util import get_platform
|
||||
|
|
@ -15,68 +17,93 @@ def show_formats():
|
|||
from distutils.fancy_getopt import FancyGetopt
|
||||
formats = []
|
||||
for format in bdist.format_commands:
|
||||
formats.append(("formats=" + format, None,
|
||||
bdist.format_command[format][1]))
|
||||
formats.append((
|
||||
'formats=' + format, None,
|
||||
bdist.format_command[format][1],
|
||||
))
|
||||
pretty_printer = FancyGetopt(formats)
|
||||
pretty_printer.print_help("List of available distribution formats:")
|
||||
pretty_printer.print_help('List of available distribution formats:')
|
||||
|
||||
|
||||
class bdist(Command):
|
||||
|
||||
description = "create a built (binary) distribution"
|
||||
description = 'create a built (binary) distribution'
|
||||
|
||||
user_options = [('bdist-base=', 'b',
|
||||
"temporary directory for creating built distributions"),
|
||||
('plat-name=', 'p',
|
||||
"platform name to embed in generated filenames "
|
||||
"(default: %s)" % get_platform()),
|
||||
('formats=', None,
|
||||
"formats for distribution (comma-separated list)"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put final built distributions in "
|
||||
"[default: dist]"),
|
||||
('skip-build', None,
|
||||
"skip rebuilding everything (for testing/debugging)"),
|
||||
('owner=', 'u',
|
||||
"Owner name used when creating a tar file"
|
||||
" [default: current user]"),
|
||||
('group=', 'g',
|
||||
"Group name used when creating a tar file"
|
||||
" [default: current group]"),
|
||||
]
|
||||
user_options = [
|
||||
(
|
||||
'bdist-base=', 'b',
|
||||
'temporary directory for creating built distributions',
|
||||
),
|
||||
(
|
||||
'plat-name=', 'p',
|
||||
'platform name to embed in generated filenames '
|
||||
'(default: %s)' % get_platform(),
|
||||
),
|
||||
(
|
||||
'formats=', None,
|
||||
'formats for distribution (comma-separated list)',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put final built distributions in '
|
||||
'[default: dist]',
|
||||
),
|
||||
(
|
||||
'skip-build', None,
|
||||
'skip rebuilding everything (for testing/debugging)',
|
||||
),
|
||||
(
|
||||
'owner=', 'u',
|
||||
'Owner name used when creating a tar file'
|
||||
' [default: current user]',
|
||||
),
|
||||
(
|
||||
'group=', 'g',
|
||||
'Group name used when creating a tar file'
|
||||
' [default: current group]',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['skip-build']
|
||||
|
||||
help_options = [
|
||||
('help-formats', None,
|
||||
"lists available distribution formats", show_formats),
|
||||
]
|
||||
(
|
||||
'help-formats', None,
|
||||
'lists available distribution formats', show_formats,
|
||||
),
|
||||
]
|
||||
|
||||
# The following commands do not take a format option from bdist
|
||||
no_format_option = ('bdist_rpm',)
|
||||
|
||||
# This won't do in reality: will need to distinguish RPM-ish Linux,
|
||||
# Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS.
|
||||
default_format = {'posix': 'gztar',
|
||||
'nt': 'zip'}
|
||||
default_format = {
|
||||
'posix': 'gztar',
|
||||
'nt': 'zip',
|
||||
}
|
||||
|
||||
# Establish the preferred order (for the --help-formats option).
|
||||
format_commands = ['rpm', 'gztar', 'bztar', 'xztar', 'ztar', 'tar',
|
||||
'wininst', 'zip', 'msi']
|
||||
format_commands = [
|
||||
'rpm', 'gztar', 'bztar', 'xztar', 'ztar', 'tar',
|
||||
'wininst', 'zip', 'msi',
|
||||
]
|
||||
|
||||
# And the real information.
|
||||
format_command = {'rpm': ('bdist_rpm', "RPM distribution"),
|
||||
'gztar': ('bdist_dumb', "gzip'ed tar file"),
|
||||
'bztar': ('bdist_dumb', "bzip2'ed tar file"),
|
||||
'xztar': ('bdist_dumb', "xz'ed tar file"),
|
||||
'ztar': ('bdist_dumb', "compressed tar file"),
|
||||
'tar': ('bdist_dumb', "tar file"),
|
||||
'wininst': ('bdist_wininst',
|
||||
"Windows executable installer"),
|
||||
'zip': ('bdist_dumb', "ZIP file"),
|
||||
'msi': ('bdist_msi', "Microsoft Installer")
|
||||
}
|
||||
|
||||
format_command = {
|
||||
'rpm': ('bdist_rpm', 'RPM distribution'),
|
||||
'gztar': ('bdist_dumb', "gzip'ed tar file"),
|
||||
'bztar': ('bdist_dumb', "bzip2'ed tar file"),
|
||||
'xztar': ('bdist_dumb', "xz'ed tar file"),
|
||||
'ztar': ('bdist_dumb', 'compressed tar file'),
|
||||
'tar': ('bdist_dumb', 'tar file'),
|
||||
'wininst': (
|
||||
'bdist_wininst',
|
||||
'Windows executable installer',
|
||||
),
|
||||
'zip': ('bdist_dumb', 'ZIP file'),
|
||||
'msi': ('bdist_msi', 'Microsoft Installer'),
|
||||
}
|
||||
|
||||
def initialize_options(self):
|
||||
self.bdist_base = None
|
||||
|
|
@ -100,8 +127,10 @@ class bdist(Command):
|
|||
# "build/bdist.<plat>/dumb", "build/bdist.<plat>/rpm", etc.)
|
||||
if self.bdist_base is None:
|
||||
build_base = self.get_finalized_command('build').build_base
|
||||
self.bdist_base = os.path.join(build_base,
|
||||
'bdist.' + self.plat_name)
|
||||
self.bdist_base = os.path.join(
|
||||
build_base,
|
||||
'bdist.' + self.plat_name,
|
||||
)
|
||||
|
||||
self.ensure_string_list('formats')
|
||||
if self.formats is None:
|
||||
|
|
@ -109,11 +138,12 @@ class bdist(Command):
|
|||
self.formats = [self.default_format[os.name]]
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to create built distributions "
|
||||
"on platform %s" % os.name)
|
||||
"don't know how to create built distributions "
|
||||
'on platform %s' % os.name,
|
||||
)
|
||||
|
||||
if self.dist_dir is None:
|
||||
self.dist_dir = "dist"
|
||||
self.dist_dir = 'dist'
|
||||
|
||||
def run(self):
|
||||
# Figure out which sub-commands we need to run.
|
||||
|
|
@ -138,6 +168,6 @@ class bdist(Command):
|
|||
|
||||
# If we're going to need to run this command again, tell it to
|
||||
# keep its temporary files around so subsequent runs go faster.
|
||||
if cmd_name in commands[i+1:]:
|
||||
if cmd_name in commands[i + 1:]:
|
||||
sub_cmd.keep_temp = 1
|
||||
self.run_command(cmd_name)
|
||||
|
|
|
|||
|
|
@ -3,49 +3,72 @@
|
|||
Implements the Distutils 'bdist_dumb' command (create a "dumb" built
|
||||
distribution -- i.e., just an archive to be unpacked under $prefix or
|
||||
$exec_prefix)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.util import get_platform
|
||||
from distutils.dir_util import remove_tree, ensure_relative
|
||||
from distutils.dir_util import ensure_relative
|
||||
from distutils.dir_util import remove_tree
|
||||
from distutils.errors import *
|
||||
from distutils.sysconfig import get_python_version
|
||||
from distutils import log
|
||||
from distutils.util import get_platform
|
||||
|
||||
|
||||
class bdist_dumb(Command):
|
||||
|
||||
description = "create a \"dumb\" built distribution"
|
||||
|
||||
user_options = [('bdist-dir=', 'd',
|
||||
"temporary directory for creating the distribution"),
|
||||
('plat-name=', 'p',
|
||||
"platform name to embed in generated filenames "
|
||||
"(default: %s)" % get_platform()),
|
||||
('format=', 'f',
|
||||
"archive format to create (tar, gztar, bztar, xztar, "
|
||||
"ztar, zip)"),
|
||||
('keep-temp', 'k',
|
||||
"keep the pseudo-installation tree around after " +
|
||||
"creating the distribution archive"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put final built distributions in"),
|
||||
('skip-build', None,
|
||||
"skip rebuilding everything (for testing/debugging)"),
|
||||
('relative', None,
|
||||
"build the archive using relative paths "
|
||||
"(default: false)"),
|
||||
('owner=', 'u',
|
||||
"Owner name used when creating a tar file"
|
||||
" [default: current user]"),
|
||||
('group=', 'g',
|
||||
"Group name used when creating a tar file"
|
||||
" [default: current group]"),
|
||||
]
|
||||
user_options = [
|
||||
(
|
||||
'bdist-dir=', 'd',
|
||||
'temporary directory for creating the distribution',
|
||||
),
|
||||
(
|
||||
'plat-name=', 'p',
|
||||
'platform name to embed in generated filenames '
|
||||
'(default: %s)' % get_platform(),
|
||||
),
|
||||
(
|
||||
'format=', 'f',
|
||||
'archive format to create (tar, gztar, bztar, xztar, '
|
||||
'ztar, zip)',
|
||||
),
|
||||
(
|
||||
'keep-temp', 'k',
|
||||
'keep the pseudo-installation tree around after ' +
|
||||
'creating the distribution archive',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put final built distributions in',
|
||||
),
|
||||
(
|
||||
'skip-build', None,
|
||||
'skip rebuilding everything (for testing/debugging)',
|
||||
),
|
||||
(
|
||||
'relative', None,
|
||||
'build the archive using relative paths '
|
||||
'(default: false)',
|
||||
),
|
||||
(
|
||||
'owner=', 'u',
|
||||
'Owner name used when creating a tar file'
|
||||
' [default: current user]',
|
||||
),
|
||||
(
|
||||
'group=', 'g',
|
||||
'Group name used when creating a tar file'
|
||||
' [default: current group]',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['keep-temp', 'skip-build', 'relative']
|
||||
|
||||
default_format = { 'posix': 'gztar',
|
||||
'nt': 'zip' }
|
||||
default_format = {'posix': 'gztar',
|
||||
'nt': 'zip', }
|
||||
|
||||
def initialize_options(self):
|
||||
self.bdist_dir = None
|
||||
|
|
@ -68,13 +91,16 @@ class bdist_dumb(Command):
|
|||
self.format = self.default_format[os.name]
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to create dumb built distributions "
|
||||
"on platform %s" % os.name)
|
||||
"don't know how to create dumb built distributions "
|
||||
'on platform %s' % os.name,
|
||||
)
|
||||
|
||||
self.set_undefined_options('bdist',
|
||||
('dist_dir', 'dist_dir'),
|
||||
('plat_name', 'plat_name'),
|
||||
('skip_build', 'skip_build'))
|
||||
self.set_undefined_options(
|
||||
'bdist',
|
||||
('dist_dir', 'dist_dir'),
|
||||
('plat_name', 'plat_name'),
|
||||
('skip_build', 'skip_build'),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
if not self.skip_build:
|
||||
|
|
@ -85,39 +111,52 @@ class bdist_dumb(Command):
|
|||
install.skip_build = self.skip_build
|
||||
install.warn_dir = 0
|
||||
|
||||
log.info("installing to %s", self.bdist_dir)
|
||||
log.info('installing to %s', self.bdist_dir)
|
||||
self.run_command('install')
|
||||
|
||||
# And make an archive relative to the root of the
|
||||
# pseudo-installation tree.
|
||||
archive_basename = "%s.%s" % (self.distribution.get_fullname(),
|
||||
self.plat_name)
|
||||
archive_basename = '{}.{}'.format(
|
||||
self.distribution.get_fullname(),
|
||||
self.plat_name,
|
||||
)
|
||||
|
||||
pseudoinstall_root = os.path.join(self.dist_dir, archive_basename)
|
||||
if not self.relative:
|
||||
archive_root = self.bdist_dir
|
||||
else:
|
||||
if (self.distribution.has_ext_modules() and
|
||||
(install.install_base != install.install_platbase)):
|
||||
if (
|
||||
self.distribution.has_ext_modules() and
|
||||
(install.install_base != install.install_platbase)
|
||||
):
|
||||
raise DistutilsPlatformError(
|
||||
"can't make a dumb built distribution where "
|
||||
"base and platbase are different (%s, %s)"
|
||||
% (repr(install.install_base),
|
||||
repr(install.install_platbase)))
|
||||
"can't make a dumb built distribution where "
|
||||
'base and platbase are different (%s, %s)'
|
||||
% (
|
||||
repr(install.install_base),
|
||||
repr(install.install_platbase),
|
||||
),
|
||||
)
|
||||
else:
|
||||
archive_root = os.path.join(self.bdist_dir,
|
||||
ensure_relative(install.install_base))
|
||||
archive_root = os.path.join(
|
||||
self.bdist_dir,
|
||||
ensure_relative(install.install_base),
|
||||
)
|
||||
|
||||
# Make the archive
|
||||
filename = self.make_archive(pseudoinstall_root,
|
||||
self.format, root_dir=archive_root,
|
||||
owner=self.owner, group=self.group)
|
||||
filename = self.make_archive(
|
||||
pseudoinstall_root,
|
||||
self.format, root_dir=archive_root,
|
||||
owner=self.owner, group=self.group,
|
||||
)
|
||||
if self.distribution.has_ext_modules():
|
||||
pyversion = get_python_version()
|
||||
else:
|
||||
pyversion = 'any'
|
||||
self.distribution.dist_files.append(('bdist_dumb', pyversion,
|
||||
filename))
|
||||
self.distribution.dist_files.append((
|
||||
'bdist_dumb', pyversion,
|
||||
filename,
|
||||
))
|
||||
|
||||
if not self.keep_temp:
|
||||
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,135 +2,225 @@
|
|||
|
||||
Implements the Distutils 'bdist_rpm' command (create RPM source and binary
|
||||
distributions)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess, sys, os
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.debug import DEBUG
|
||||
from distutils.file_util import write_file
|
||||
from distutils.errors import *
|
||||
from distutils.file_util import write_file
|
||||
from distutils.sysconfig import get_python_version
|
||||
from distutils import log
|
||||
|
||||
|
||||
class bdist_rpm(Command):
|
||||
|
||||
description = "create an RPM distribution"
|
||||
description = 'create an RPM distribution'
|
||||
|
||||
user_options = [
|
||||
('bdist-base=', None,
|
||||
"base directory for creating built distributions"),
|
||||
('rpm-base=', None,
|
||||
"base directory for creating RPMs (defaults to \"rpm\" under "
|
||||
"--bdist-base; must be specified for RPM 2)"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put final RPM files in "
|
||||
"(and .spec files if --spec-only)"),
|
||||
('python=', None,
|
||||
"path to Python interpreter to hard-code in the .spec file "
|
||||
"(default: \"python\")"),
|
||||
('fix-python', None,
|
||||
"hard-code the exact path to the current Python interpreter in "
|
||||
"the .spec file"),
|
||||
('spec-only', None,
|
||||
"only regenerate spec file"),
|
||||
('source-only', None,
|
||||
"only generate source RPM"),
|
||||
('binary-only', None,
|
||||
"only generate binary RPM"),
|
||||
('use-bzip2', None,
|
||||
"use bzip2 instead of gzip to create source distribution"),
|
||||
(
|
||||
'bdist-base=', None,
|
||||
'base directory for creating built distributions',
|
||||
),
|
||||
(
|
||||
'rpm-base=', None,
|
||||
"base directory for creating RPMs (defaults to \"rpm\" under "
|
||||
'--bdist-base; must be specified for RPM 2)',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put final RPM files in '
|
||||
'(and .spec files if --spec-only)',
|
||||
),
|
||||
(
|
||||
'python=', None,
|
||||
'path to Python interpreter to hard-code in the .spec file '
|
||||
"(default: \"python\")",
|
||||
),
|
||||
(
|
||||
'fix-python', None,
|
||||
'hard-code the exact path to the current Python interpreter in '
|
||||
'the .spec file',
|
||||
),
|
||||
(
|
||||
'spec-only', None,
|
||||
'only regenerate spec file',
|
||||
),
|
||||
(
|
||||
'source-only', None,
|
||||
'only generate source RPM',
|
||||
),
|
||||
(
|
||||
'binary-only', None,
|
||||
'only generate binary RPM',
|
||||
),
|
||||
(
|
||||
'use-bzip2', None,
|
||||
'use bzip2 instead of gzip to create source distribution',
|
||||
),
|
||||
|
||||
# More meta-data: too RPM-specific to put in the setup script,
|
||||
# but needs to go in the .spec file -- so we make these options
|
||||
# to "bdist_rpm". The idea is that packagers would put this
|
||||
# info in setup.cfg, although they are of course free to
|
||||
# supply it on the command line.
|
||||
('distribution-name=', None,
|
||||
"name of the (Linux) distribution to which this "
|
||||
"RPM applies (*not* the name of the module distribution!)"),
|
||||
('group=', None,
|
||||
"package classification [default: \"Development/Libraries\"]"),
|
||||
('release=', None,
|
||||
"RPM release number"),
|
||||
('serial=', None,
|
||||
"RPM serial number"),
|
||||
('vendor=', None,
|
||||
"RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") "
|
||||
"[default: maintainer or author from setup script]"),
|
||||
('packager=', None,
|
||||
"RPM packager (eg. \"Jane Doe <jane@example.net>\") "
|
||||
"[default: vendor]"),
|
||||
('doc-files=', None,
|
||||
"list of documentation files (space or comma-separated)"),
|
||||
('changelog=', None,
|
||||
"RPM changelog"),
|
||||
('icon=', None,
|
||||
"name of icon file"),
|
||||
('provides=', None,
|
||||
"capabilities provided by this package"),
|
||||
('requires=', None,
|
||||
"capabilities required by this package"),
|
||||
('conflicts=', None,
|
||||
"capabilities which conflict with this package"),
|
||||
('build-requires=', None,
|
||||
"capabilities required to build this package"),
|
||||
('obsoletes=', None,
|
||||
"capabilities made obsolete by this package"),
|
||||
('no-autoreq', None,
|
||||
"do not automatically calculate dependencies"),
|
||||
(
|
||||
'distribution-name=', None,
|
||||
'name of the (Linux) distribution to which this '
|
||||
'RPM applies (*not* the name of the module distribution!)',
|
||||
),
|
||||
(
|
||||
'group=', None,
|
||||
"package classification [default: \"Development/Libraries\"]",
|
||||
),
|
||||
(
|
||||
'release=', None,
|
||||
'RPM release number',
|
||||
),
|
||||
(
|
||||
'serial=', None,
|
||||
'RPM serial number',
|
||||
),
|
||||
(
|
||||
'vendor=', None,
|
||||
"RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") "
|
||||
'[default: maintainer or author from setup script]',
|
||||
),
|
||||
(
|
||||
'packager=', None,
|
||||
"RPM packager (eg. \"Jane Doe <jane@example.net>\") "
|
||||
'[default: vendor]',
|
||||
),
|
||||
(
|
||||
'doc-files=', None,
|
||||
'list of documentation files (space or comma-separated)',
|
||||
),
|
||||
(
|
||||
'changelog=', None,
|
||||
'RPM changelog',
|
||||
),
|
||||
(
|
||||
'icon=', None,
|
||||
'name of icon file',
|
||||
),
|
||||
(
|
||||
'provides=', None,
|
||||
'capabilities provided by this package',
|
||||
),
|
||||
(
|
||||
'requires=', None,
|
||||
'capabilities required by this package',
|
||||
),
|
||||
(
|
||||
'conflicts=', None,
|
||||
'capabilities which conflict with this package',
|
||||
),
|
||||
(
|
||||
'build-requires=', None,
|
||||
'capabilities required to build this package',
|
||||
),
|
||||
(
|
||||
'obsoletes=', None,
|
||||
'capabilities made obsolete by this package',
|
||||
),
|
||||
(
|
||||
'no-autoreq', None,
|
||||
'do not automatically calculate dependencies',
|
||||
),
|
||||
|
||||
# Actions to take when building RPM
|
||||
('keep-temp', 'k',
|
||||
"don't clean up RPM build directory"),
|
||||
('no-keep-temp', None,
|
||||
"clean up RPM build directory [default]"),
|
||||
('use-rpm-opt-flags', None,
|
||||
"compile with RPM_OPT_FLAGS when building from source RPM"),
|
||||
('no-rpm-opt-flags', None,
|
||||
"do not pass any RPM CFLAGS to compiler"),
|
||||
('rpm3-mode', None,
|
||||
"RPM 3 compatibility mode (default)"),
|
||||
('rpm2-mode', None,
|
||||
"RPM 2 compatibility mode"),
|
||||
(
|
||||
'keep-temp', 'k',
|
||||
"don't clean up RPM build directory",
|
||||
),
|
||||
(
|
||||
'no-keep-temp', None,
|
||||
'clean up RPM build directory [default]',
|
||||
),
|
||||
(
|
||||
'use-rpm-opt-flags', None,
|
||||
'compile with RPM_OPT_FLAGS when building from source RPM',
|
||||
),
|
||||
(
|
||||
'no-rpm-opt-flags', None,
|
||||
'do not pass any RPM CFLAGS to compiler',
|
||||
),
|
||||
(
|
||||
'rpm3-mode', None,
|
||||
'RPM 3 compatibility mode (default)',
|
||||
),
|
||||
(
|
||||
'rpm2-mode', None,
|
||||
'RPM 2 compatibility mode',
|
||||
),
|
||||
|
||||
# Add the hooks necessary for specifying custom scripts
|
||||
('prep-script=', None,
|
||||
"Specify a script for the PREP phase of RPM building"),
|
||||
('build-script=', None,
|
||||
"Specify a script for the BUILD phase of RPM building"),
|
||||
(
|
||||
'prep-script=', None,
|
||||
'Specify a script for the PREP phase of RPM building',
|
||||
),
|
||||
(
|
||||
'build-script=', None,
|
||||
'Specify a script for the BUILD phase of RPM building',
|
||||
),
|
||||
|
||||
('pre-install=', None,
|
||||
"Specify a script for the pre-INSTALL phase of RPM building"),
|
||||
('install-script=', None,
|
||||
"Specify a script for the INSTALL phase of RPM building"),
|
||||
('post-install=', None,
|
||||
"Specify a script for the post-INSTALL phase of RPM building"),
|
||||
(
|
||||
'pre-install=', None,
|
||||
'Specify a script for the pre-INSTALL phase of RPM building',
|
||||
),
|
||||
(
|
||||
'install-script=', None,
|
||||
'Specify a script for the INSTALL phase of RPM building',
|
||||
),
|
||||
(
|
||||
'post-install=', None,
|
||||
'Specify a script for the post-INSTALL phase of RPM building',
|
||||
),
|
||||
|
||||
('pre-uninstall=', None,
|
||||
"Specify a script for the pre-UNINSTALL phase of RPM building"),
|
||||
('post-uninstall=', None,
|
||||
"Specify a script for the post-UNINSTALL phase of RPM building"),
|
||||
(
|
||||
'pre-uninstall=', None,
|
||||
'Specify a script for the pre-UNINSTALL phase of RPM building',
|
||||
),
|
||||
(
|
||||
'post-uninstall=', None,
|
||||
'Specify a script for the post-UNINSTALL phase of RPM building',
|
||||
),
|
||||
|
||||
('clean-script=', None,
|
||||
"Specify a script for the CLEAN phase of RPM building"),
|
||||
(
|
||||
'clean-script=', None,
|
||||
'Specify a script for the CLEAN phase of RPM building',
|
||||
),
|
||||
|
||||
('verify-script=', None,
|
||||
"Specify a script for the VERIFY phase of the RPM build"),
|
||||
(
|
||||
'verify-script=', None,
|
||||
'Specify a script for the VERIFY phase of the RPM build',
|
||||
),
|
||||
|
||||
# Allow a packager to explicitly force an architecture
|
||||
('force-arch=', None,
|
||||
"Force an architecture onto the RPM build process"),
|
||||
(
|
||||
'force-arch=', None,
|
||||
'Force an architecture onto the RPM build process',
|
||||
),
|
||||
|
||||
('quiet', 'q',
|
||||
"Run the INSTALL phase of RPM building in quiet mode"),
|
||||
]
|
||||
(
|
||||
'quiet', 'q',
|
||||
'Run the INSTALL phase of RPM building in quiet mode',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['keep-temp', 'use-rpm-opt-flags', 'rpm3-mode',
|
||||
'no-autoreq', 'quiet']
|
||||
|
||||
negative_opt = {'no-keep-temp': 'keep-temp',
|
||||
'no-rpm-opt-flags': 'use-rpm-opt-flags',
|
||||
'rpm2-mode': 'rpm3-mode'}
|
||||
boolean_options = [
|
||||
'keep-temp', 'use-rpm-opt-flags', 'rpm3-mode',
|
||||
'no-autoreq', 'quiet',
|
||||
]
|
||||
|
||||
negative_opt = {
|
||||
'no-keep-temp': 'keep-temp',
|
||||
'no-rpm-opt-flags': 'use-rpm-opt-flags',
|
||||
'rpm2-mode': 'rpm3-mode',
|
||||
}
|
||||
|
||||
def initialize_options(self):
|
||||
self.bdist_base = None
|
||||
|
|
@ -182,24 +272,29 @@ class bdist_rpm(Command):
|
|||
if self.rpm_base is None:
|
||||
if not self.rpm3_mode:
|
||||
raise DistutilsOptionError(
|
||||
"you must specify --rpm-base in RPM 2 mode")
|
||||
self.rpm_base = os.path.join(self.bdist_base, "rpm")
|
||||
'you must specify --rpm-base in RPM 2 mode',
|
||||
)
|
||||
self.rpm_base = os.path.join(self.bdist_base, 'rpm')
|
||||
|
||||
if self.python is None:
|
||||
if self.fix_python:
|
||||
self.python = sys.executable
|
||||
else:
|
||||
self.python = "python3"
|
||||
self.python = 'python3'
|
||||
elif self.fix_python:
|
||||
raise DistutilsOptionError(
|
||||
"--python and --fix-python are mutually exclusive options")
|
||||
'--python and --fix-python are mutually exclusive options',
|
||||
)
|
||||
|
||||
if os.name != 'posix':
|
||||
raise DistutilsPlatformError("don't know how to create RPM "
|
||||
"distributions on platform %s" % os.name)
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to create RPM "
|
||||
'distributions on platform %s' % os.name,
|
||||
)
|
||||
if self.binary_only and self.source_only:
|
||||
raise DistutilsOptionError(
|
||||
"cannot supply both '--source-only' and '--binary-only'")
|
||||
"cannot supply both '--source-only' and '--binary-only'",
|
||||
)
|
||||
|
||||
# don't pass CFLAGS to pure python distributions
|
||||
if not self.distribution.has_ext_modules():
|
||||
|
|
@ -209,10 +304,14 @@ class bdist_rpm(Command):
|
|||
self.finalize_package_data()
|
||||
|
||||
def finalize_package_data(self):
|
||||
self.ensure_string('group', "Development/Libraries")
|
||||
self.ensure_string('vendor',
|
||||
"%s <%s>" % (self.distribution.get_contact(),
|
||||
self.distribution.get_contact_email()))
|
||||
self.ensure_string('group', 'Development/Libraries')
|
||||
self.ensure_string(
|
||||
'vendor',
|
||||
'{} <{}>'.format(
|
||||
self.distribution.get_contact(),
|
||||
self.distribution.get_contact_email(),
|
||||
),
|
||||
)
|
||||
self.ensure_string('packager')
|
||||
self.ensure_string_list('doc_files')
|
||||
if isinstance(self.doc_files, list):
|
||||
|
|
@ -220,13 +319,13 @@ class bdist_rpm(Command):
|
|||
if os.path.exists(readme) and readme not in self.doc_files:
|
||||
self.doc_files.append(readme)
|
||||
|
||||
self.ensure_string('release', "1")
|
||||
self.ensure_string('release', '1')
|
||||
self.ensure_string('serial') # should it be an int?
|
||||
|
||||
self.ensure_string('distribution_name')
|
||||
|
||||
self.ensure_string('changelog')
|
||||
# Format changelog correctly
|
||||
# Format changelog correctly
|
||||
self.changelog = self._format_changelog(self.changelog)
|
||||
|
||||
self.ensure_filename('icon')
|
||||
|
|
@ -255,11 +354,11 @@ class bdist_rpm(Command):
|
|||
|
||||
def run(self):
|
||||
if DEBUG:
|
||||
print("before _get_package_data():")
|
||||
print("vendor =", self.vendor)
|
||||
print("packager =", self.packager)
|
||||
print("doc_files =", self.doc_files)
|
||||
print("changelog =", self.changelog)
|
||||
print('before _get_package_data():')
|
||||
print('vendor =', self.vendor)
|
||||
print('packager =', self.packager)
|
||||
print('doc_files =', self.doc_files)
|
||||
print('changelog =', self.changelog)
|
||||
|
||||
# make directories
|
||||
if self.spec_only:
|
||||
|
|
@ -274,14 +373,20 @@ class bdist_rpm(Command):
|
|||
|
||||
# Spec file goes into 'dist_dir' if '--spec-only specified',
|
||||
# build/rpm.<plat> otherwise.
|
||||
spec_path = os.path.join(spec_dir,
|
||||
"%s.spec" % self.distribution.get_name())
|
||||
self.execute(write_file,
|
||||
(spec_path,
|
||||
self._make_spec_file()),
|
||||
"writing '%s'" % spec_path)
|
||||
spec_path = os.path.join(
|
||||
spec_dir,
|
||||
'%s.spec' % self.distribution.get_name(),
|
||||
)
|
||||
self.execute(
|
||||
write_file,
|
||||
(
|
||||
spec_path,
|
||||
self._make_spec_file(),
|
||||
),
|
||||
"writing '%s'" % spec_path,
|
||||
)
|
||||
|
||||
if self.spec_only: # stop if requested
|
||||
if self.spec_only: # stop if requested
|
||||
return
|
||||
|
||||
# Make a source distribution and copy to SOURCES directory with
|
||||
|
|
@ -304,13 +409,14 @@ class bdist_rpm(Command):
|
|||
self.copy_file(self.icon, source_dir)
|
||||
else:
|
||||
raise DistutilsFileError(
|
||||
"icon file '%s' does not exist" % self.icon)
|
||||
"icon file '%s' does not exist" % self.icon,
|
||||
)
|
||||
|
||||
# build package
|
||||
log.info("building RPMs")
|
||||
log.info('building RPMs')
|
||||
rpm_cmd = ['rpmbuild']
|
||||
|
||||
if self.source_only: # what kind of RPMs?
|
||||
if self.source_only: # what kind of RPMs?
|
||||
rpm_cmd.append('-bs')
|
||||
elif self.binary_only:
|
||||
rpm_cmd.append('-bb')
|
||||
|
|
@ -318,8 +424,10 @@ class bdist_rpm(Command):
|
|||
rpm_cmd.append('-ba')
|
||||
rpm_cmd.extend(['--define', '__python %s' % self.python])
|
||||
if self.rpm3_mode:
|
||||
rpm_cmd.extend(['--define',
|
||||
'_topdir %s' % os.path.abspath(self.rpm_base)])
|
||||
rpm_cmd.extend([
|
||||
'--define',
|
||||
'_topdir %s' % os.path.abspath(self.rpm_base),
|
||||
])
|
||||
if not self.keep_temp:
|
||||
rpm_cmd.append('--clean')
|
||||
|
||||
|
|
@ -331,11 +439,12 @@ class bdist_rpm(Command):
|
|||
# file
|
||||
# Note that some of these may not be really built (if the file
|
||||
# list is empty)
|
||||
nvr_string = "%{name}-%{version}-%{release}"
|
||||
src_rpm = nvr_string + ".src.rpm"
|
||||
non_src_rpm = "%{arch}/" + nvr_string + ".%{arch}.rpm"
|
||||
q_cmd = r"rpm -q --qf '%s %s\n' --specfile '%s'" % (
|
||||
src_rpm, non_src_rpm, spec_path)
|
||||
nvr_string = '%{name}-%{version}-%{release}'
|
||||
src_rpm = nvr_string + '.src.rpm'
|
||||
non_src_rpm = '%{arch}/' + nvr_string + '.%{arch}.rpm'
|
||||
q_cmd = r"rpm -q --qf '{} {}\n' --specfile '{}'".format(
|
||||
src_rpm, non_src_rpm, spec_path,
|
||||
)
|
||||
|
||||
out = os.popen(q_cmd)
|
||||
try:
|
||||
|
|
@ -346,7 +455,7 @@ class bdist_rpm(Command):
|
|||
if not line:
|
||||
break
|
||||
l = line.strip().split()
|
||||
assert(len(l) == 2)
|
||||
assert (len(l) == 2)
|
||||
binary_rpms.append(l[1])
|
||||
# The source rpm is named after the first entry in the spec file
|
||||
if source_rpm is None:
|
||||
|
|
@ -354,7 +463,7 @@ class bdist_rpm(Command):
|
|||
|
||||
status = out.close()
|
||||
if status:
|
||||
raise DistutilsExecError("Failed to execute: %s" % repr(q_cmd))
|
||||
raise DistutilsExecError('Failed to execute: %s' % repr(q_cmd))
|
||||
|
||||
finally:
|
||||
out.close()
|
||||
|
|
@ -369,21 +478,25 @@ class bdist_rpm(Command):
|
|||
|
||||
if not self.binary_only:
|
||||
srpm = os.path.join(rpm_dir['SRPMS'], source_rpm)
|
||||
assert(os.path.exists(srpm))
|
||||
assert (os.path.exists(srpm))
|
||||
self.move_file(srpm, self.dist_dir)
|
||||
filename = os.path.join(self.dist_dir, source_rpm)
|
||||
self.distribution.dist_files.append(
|
||||
('bdist_rpm', pyversion, filename))
|
||||
('bdist_rpm', pyversion, filename),
|
||||
)
|
||||
|
||||
if not self.source_only:
|
||||
for rpm in binary_rpms:
|
||||
rpm = os.path.join(rpm_dir['RPMS'], rpm)
|
||||
if os.path.exists(rpm):
|
||||
self.move_file(rpm, self.dist_dir)
|
||||
filename = os.path.join(self.dist_dir,
|
||||
os.path.basename(rpm))
|
||||
filename = os.path.join(
|
||||
self.dist_dir,
|
||||
os.path.basename(rpm),
|
||||
)
|
||||
self.distribution.dist_files.append(
|
||||
('bdist_rpm', pyversion, filename))
|
||||
('bdist_rpm', pyversion, filename),
|
||||
)
|
||||
|
||||
def _dist_path(self, path):
|
||||
return os.path.join(self.dist_dir, os.path.basename(path))
|
||||
|
|
@ -395,12 +508,12 @@ class bdist_rpm(Command):
|
|||
# definitions and headers
|
||||
spec_file = [
|
||||
'%define name ' + self.distribution.get_name(),
|
||||
'%define version ' + self.distribution.get_version().replace('-','_'),
|
||||
'%define version ' + self.distribution.get_version().replace('-', '_'),
|
||||
'%define unmangled_version ' + self.distribution.get_version(),
|
||||
'%define release ' + self.release.replace('-','_'),
|
||||
'%define release ' + self.release.replace('-', '_'),
|
||||
'',
|
||||
'Summary: ' + self.distribution.get_description(),
|
||||
]
|
||||
]
|
||||
|
||||
# Workaround for #14443 which affects some RPM based systems such as
|
||||
# RHEL6 (and probably derivatives)
|
||||
|
|
@ -408,10 +521,12 @@ class bdist_rpm(Command):
|
|||
# Generate a potential replacement value for __os_install_post (whilst
|
||||
# normalizing the whitespace to simplify the test for whether the
|
||||
# invocation of brp-python-bytecompile passes in __python):
|
||||
vendor_hook = '\n'.join([' %s \\' % line.strip()
|
||||
for line in vendor_hook.splitlines()])
|
||||
problem = "brp-python-bytecompile \\\n"
|
||||
fixed = "brp-python-bytecompile %{__python} \\\n"
|
||||
vendor_hook = '\n'.join([
|
||||
' %s \\' % line.strip()
|
||||
for line in vendor_hook.splitlines()
|
||||
])
|
||||
problem = 'brp-python-bytecompile \\\n'
|
||||
fixed = 'brp-python-bytecompile %{__python} \\\n'
|
||||
fixed_hook = vendor_hook.replace(problem, fixed)
|
||||
if fixed_hook != vendor_hook:
|
||||
spec_file.append('# Workaround for http://bugs.python.org/issue14443')
|
||||
|
|
@ -427,7 +542,8 @@ class bdist_rpm(Command):
|
|||
spec_file.extend([
|
||||
'Name: %{name}',
|
||||
'Version: %{version}',
|
||||
'Release: %{release}',])
|
||||
'Release: %{release}',
|
||||
])
|
||||
|
||||
# XXX yuck! this filename is available from the "sdist" command,
|
||||
# but only after it has run: and we create the spec file before
|
||||
|
|
@ -448,21 +564,21 @@ class bdist_rpm(Command):
|
|||
if not self.distribution.has_ext_modules():
|
||||
spec_file.append('BuildArch: noarch')
|
||||
else:
|
||||
spec_file.append( 'BuildArch: %s' % self.force_arch )
|
||||
spec_file.append('BuildArch: %s' % self.force_arch)
|
||||
|
||||
for field in ('Vendor',
|
||||
'Packager',
|
||||
'Provides',
|
||||
'Requires',
|
||||
'Conflicts',
|
||||
'Obsoletes',
|
||||
):
|
||||
for field in (
|
||||
'Vendor',
|
||||
'Packager',
|
||||
'Provides',
|
||||
'Requires',
|
||||
'Conflicts',
|
||||
'Obsoletes',
|
||||
):
|
||||
val = getattr(self, field.lower())
|
||||
if isinstance(val, list):
|
||||
spec_file.append('%s: %s' % (field, ' '.join(val)))
|
||||
spec_file.append('{}: {}'.format(field, ' '.join(val)))
|
||||
elif val is not None:
|
||||
spec_file.append('%s: %s' % (field, val))
|
||||
|
||||
spec_file.append('{}: {}'.format(field, val))
|
||||
|
||||
if self.distribution.get_url() != 'UNKNOWN':
|
||||
spec_file.append('Url: ' + self.distribution.get_url())
|
||||
|
|
@ -471,8 +587,10 @@ class bdist_rpm(Command):
|
|||
spec_file.append('Distribution: ' + self.distribution_name)
|
||||
|
||||
if self.build_requires:
|
||||
spec_file.append('BuildRequires: ' +
|
||||
' '.join(self.build_requires))
|
||||
spec_file.append(
|
||||
'BuildRequires: ' +
|
||||
' '.join(self.build_requires),
|
||||
)
|
||||
|
||||
if self.icon:
|
||||
spec_file.append('Icon: ' + os.path.basename(self.icon))
|
||||
|
|
@ -483,8 +601,8 @@ class bdist_rpm(Command):
|
|||
spec_file.extend([
|
||||
'',
|
||||
'%description',
|
||||
self.distribution.get_long_description()
|
||||
])
|
||||
self.distribution.get_long_description(),
|
||||
])
|
||||
|
||||
# put locale descriptions into spec file
|
||||
# XXX again, suppressed because config file syntax doesn't
|
||||
|
|
@ -498,8 +616,8 @@ class bdist_rpm(Command):
|
|||
|
||||
# rpm scripts
|
||||
# figure out default build script
|
||||
def_setup_call = "%s %s" % (self.python,os.path.basename(sys.argv[0]))
|
||||
def_build = "%s build" % def_setup_call
|
||||
def_setup_call = '{} {}'.format(self.python, os.path.basename(sys.argv[0]))
|
||||
def_build = '%s build' % def_setup_call
|
||||
if self.use_rpm_opt_flags:
|
||||
def_build = 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build
|
||||
|
||||
|
|
@ -509,14 +627,16 @@ class bdist_rpm(Command):
|
|||
# that we open and interpolate into the spec file, but the defaults
|
||||
# are just text that we drop in as-is. Hmmm.
|
||||
|
||||
install_cmd = ('%s install -O1 --root=$RPM_BUILD_ROOT '
|
||||
'--record=INSTALLED_FILES') % def_setup_call
|
||||
install_cmd = (
|
||||
'%s install -O1 --root=$RPM_BUILD_ROOT '
|
||||
'--record=INSTALLED_FILES'
|
||||
) % def_setup_call
|
||||
|
||||
script_options = [
|
||||
('prep', 'prep_script', "%setup -n %{name}-%{unmangled_version}"),
|
||||
('prep', 'prep_script', '%setup -n %{name}-%{unmangled_version}'),
|
||||
('build', 'build_script', def_build),
|
||||
('install', 'install_script', install_cmd),
|
||||
('clean', 'clean_script', "rm -rf $RPM_BUILD_ROOT"),
|
||||
('clean', 'clean_script', 'rm -rf $RPM_BUILD_ROOT'),
|
||||
('verifyscript', 'verify_script', None),
|
||||
('pre', 'pre_install', None),
|
||||
('post', 'post_install', None),
|
||||
|
|
@ -531,20 +651,20 @@ class bdist_rpm(Command):
|
|||
if val or default:
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%' + rpm_opt,])
|
||||
'%' + rpm_opt,
|
||||
])
|
||||
if val:
|
||||
with open(val) as f:
|
||||
spec_file.extend(f.read().split('\n'))
|
||||
else:
|
||||
spec_file.append(default)
|
||||
|
||||
|
||||
# files section
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%files -f INSTALLED_FILES',
|
||||
'%defattr(-,root,root)',
|
||||
])
|
||||
])
|
||||
|
||||
if self.doc_files:
|
||||
spec_file.append('%doc ' + ' '.join(self.doc_files))
|
||||
|
|
@ -552,7 +672,8 @@ class bdist_rpm(Command):
|
|||
if self.changelog:
|
||||
spec_file.extend([
|
||||
'',
|
||||
'%changelog',])
|
||||
'%changelog',
|
||||
])
|
||||
spec_file.extend(self.changelog)
|
||||
|
||||
return spec_file
|
||||
|
|
|
|||
|
|
@ -2,69 +2,103 @@
|
|||
|
||||
Implements the Distutils 'bdist_wininst' command: create a windows installer
|
||||
exe-program."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.util import get_platform
|
||||
from distutils.dir_util import remove_tree
|
||||
from distutils.errors import *
|
||||
from distutils.sysconfig import get_python_version
|
||||
from distutils import log
|
||||
from distutils.util import get_platform
|
||||
|
||||
|
||||
class bdist_wininst(Command):
|
||||
|
||||
description = "create an executable installer for MS Windows"
|
||||
description = 'create an executable installer for MS Windows'
|
||||
|
||||
user_options = [('bdist-dir=', None,
|
||||
"temporary directory for creating the distribution"),
|
||||
('plat-name=', 'p',
|
||||
"platform name to embed in generated filenames "
|
||||
"(default: %s)" % get_platform()),
|
||||
('keep-temp', 'k',
|
||||
"keep the pseudo-installation tree around after " +
|
||||
"creating the distribution archive"),
|
||||
('target-version=', None,
|
||||
"require a specific python version" +
|
||||
" on the target system"),
|
||||
('no-target-compile', 'c',
|
||||
"do not compile .py to .pyc on the target system"),
|
||||
('no-target-optimize', 'o',
|
||||
"do not compile .py to .pyo (optimized) "
|
||||
"on the target system"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put final built distributions in"),
|
||||
('bitmap=', 'b',
|
||||
"bitmap to use for the installer instead of python-powered logo"),
|
||||
('title=', 't',
|
||||
"title to display on the installer background instead of default"),
|
||||
('skip-build', None,
|
||||
"skip rebuilding everything (for testing/debugging)"),
|
||||
('install-script=', None,
|
||||
"basename of installation script to be run after "
|
||||
"installation or before deinstallation"),
|
||||
('pre-install-script=', None,
|
||||
"Fully qualified filename of a script to be run before "
|
||||
"any files are installed. This script need not be in the "
|
||||
"distribution"),
|
||||
('user-access-control=', None,
|
||||
"specify Vista's UAC handling - 'none'/default=no "
|
||||
"handling, 'auto'=use UAC if target Python installed for "
|
||||
"all users, 'force'=always use UAC"),
|
||||
]
|
||||
user_options = [
|
||||
(
|
||||
'bdist-dir=', None,
|
||||
'temporary directory for creating the distribution',
|
||||
),
|
||||
(
|
||||
'plat-name=', 'p',
|
||||
'platform name to embed in generated filenames '
|
||||
'(default: %s)' % get_platform(),
|
||||
),
|
||||
(
|
||||
'keep-temp', 'k',
|
||||
'keep the pseudo-installation tree around after ' +
|
||||
'creating the distribution archive',
|
||||
),
|
||||
(
|
||||
'target-version=', None,
|
||||
'require a specific python version' +
|
||||
' on the target system',
|
||||
),
|
||||
(
|
||||
'no-target-compile', 'c',
|
||||
'do not compile .py to .pyc on the target system',
|
||||
),
|
||||
(
|
||||
'no-target-optimize', 'o',
|
||||
'do not compile .py to .pyo (optimized) '
|
||||
'on the target system',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put final built distributions in',
|
||||
),
|
||||
(
|
||||
'bitmap=', 'b',
|
||||
'bitmap to use for the installer instead of python-powered logo',
|
||||
),
|
||||
(
|
||||
'title=', 't',
|
||||
'title to display on the installer background instead of default',
|
||||
),
|
||||
(
|
||||
'skip-build', None,
|
||||
'skip rebuilding everything (for testing/debugging)',
|
||||
),
|
||||
(
|
||||
'install-script=', None,
|
||||
'basename of installation script to be run after '
|
||||
'installation or before deinstallation',
|
||||
),
|
||||
(
|
||||
'pre-install-script=', None,
|
||||
'Fully qualified filename of a script to be run before '
|
||||
'any files are installed. This script need not be in the '
|
||||
'distribution',
|
||||
),
|
||||
(
|
||||
'user-access-control=', None,
|
||||
"specify Vista's UAC handling - 'none'/default=no "
|
||||
"handling, 'auto'=use UAC if target Python installed for "
|
||||
"all users, 'force'=always use UAC",
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize',
|
||||
'skip-build']
|
||||
boolean_options = [
|
||||
'keep-temp', 'no-target-compile', 'no-target-optimize',
|
||||
'skip-build',
|
||||
]
|
||||
|
||||
# bpo-10945: bdist_wininst requires mbcs encoding only available on Windows
|
||||
_unsupported = (sys.platform != "win32")
|
||||
_unsupported = (sys.platform != 'win32')
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
super().__init__(*args, **kw)
|
||||
warnings.warn("bdist_wininst command is deprecated since Python 3.8, "
|
||||
"use bdist_wheel (wheel packages) instead",
|
||||
DeprecationWarning, 2)
|
||||
warnings.warn(
|
||||
'bdist_wininst command is deprecated since Python 3.8, '
|
||||
'use bdist_wheel (wheel packages) instead',
|
||||
DeprecationWarning, 2,
|
||||
)
|
||||
|
||||
def initialize_options(self):
|
||||
self.bdist_dir = None
|
||||
|
|
@ -81,7 +115,6 @@ class bdist_wininst(Command):
|
|||
self.pre_install_script = None
|
||||
self.user_access_control = None
|
||||
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('bdist', ('skip_build', 'skip_build'))
|
||||
|
||||
|
|
@ -96,20 +129,22 @@ class bdist_wininst(Command):
|
|||
self.bdist_dir = os.path.join(bdist_base, 'wininst')
|
||||
|
||||
if not self.target_version:
|
||||
self.target_version = ""
|
||||
self.target_version = ''
|
||||
|
||||
if not self.skip_build and self.distribution.has_ext_modules():
|
||||
short_version = get_python_version()
|
||||
if self.target_version and self.target_version != short_version:
|
||||
raise DistutilsOptionError(
|
||||
"target version can only be %s, or the '--skip-build'" \
|
||||
" option must be specified" % (short_version,))
|
||||
"target version can only be %s, or the '--skip-build'"
|
||||
' option must be specified' % (short_version,),
|
||||
)
|
||||
self.target_version = short_version
|
||||
|
||||
self.set_undefined_options('bdist',
|
||||
('dist_dir', 'dist_dir'),
|
||||
('plat_name', 'plat_name'),
|
||||
)
|
||||
self.set_undefined_options(
|
||||
'bdist',
|
||||
('dist_dir', 'dist_dir'),
|
||||
('plat_name', 'plat_name'),
|
||||
)
|
||||
|
||||
if self.install_script:
|
||||
for script in self.distribution.scripts:
|
||||
|
|
@ -117,16 +152,22 @@ class bdist_wininst(Command):
|
|||
break
|
||||
else:
|
||||
raise DistutilsOptionError(
|
||||
"install_script '%s' not found in scripts"
|
||||
% self.install_script)
|
||||
"install_script '%s' not found in scripts"
|
||||
% self.install_script,
|
||||
)
|
||||
|
||||
def run(self):
|
||||
if (sys.platform != "win32" and
|
||||
(self.distribution.has_ext_modules() or
|
||||
self.distribution.has_c_libraries())):
|
||||
raise DistutilsPlatformError \
|
||||
("distribution contains extensions and/or C libraries; "
|
||||
"must be compiled on a Windows 32 platform")
|
||||
if (
|
||||
sys.platform != 'win32' and
|
||||
(
|
||||
self.distribution.has_ext_modules() or
|
||||
self.distribution.has_c_libraries()
|
||||
)
|
||||
):
|
||||
raise DistutilsPlatformError(
|
||||
'distribution contains extensions and/or C libraries; '
|
||||
'must be compiled on a Windows 32 platform',
|
||||
)
|
||||
|
||||
if not self.skip_build:
|
||||
self.run_command('build')
|
||||
|
|
@ -151,12 +192,14 @@ class bdist_wininst(Command):
|
|||
# version.
|
||||
target_version = self.target_version
|
||||
if not target_version:
|
||||
assert self.skip_build, "Should have already checked this"
|
||||
assert self.skip_build, 'Should have already checked this'
|
||||
target_version = '%d.%d' % sys.version_info[:2]
|
||||
plat_specifier = ".%s-%s" % (self.plat_name, target_version)
|
||||
plat_specifier = '.{}-{}'.format(self.plat_name, target_version)
|
||||
build = self.get_finalized_command('build')
|
||||
build.build_lib = os.path.join(build.build_base,
|
||||
'lib' + plat_specifier)
|
||||
build.build_lib = os.path.join(
|
||||
build.build_base,
|
||||
'lib' + plat_specifier,
|
||||
)
|
||||
|
||||
# Use a custom scheme for the zip-file, because we have to decide
|
||||
# at installation time which scheme to use.
|
||||
|
|
@ -164,11 +207,13 @@ class bdist_wininst(Command):
|
|||
value = key.upper()
|
||||
if key == 'headers':
|
||||
value = value + '/Include/$dist_name'
|
||||
setattr(install,
|
||||
'install_' + key,
|
||||
value)
|
||||
setattr(
|
||||
install,
|
||||
'install_' + key,
|
||||
value,
|
||||
)
|
||||
|
||||
log.info("installing to %s", self.bdist_dir)
|
||||
log.info('installing to %s', self.bdist_dir)
|
||||
install.ensure_finalized()
|
||||
|
||||
# avoid warning of 'install_lib' about installing
|
||||
|
|
@ -184,16 +229,20 @@ class bdist_wininst(Command):
|
|||
from tempfile import mktemp
|
||||
archive_basename = mktemp()
|
||||
fullname = self.distribution.get_fullname()
|
||||
arcname = self.make_archive(archive_basename, "zip",
|
||||
root_dir=self.bdist_dir)
|
||||
arcname = self.make_archive(
|
||||
archive_basename, 'zip',
|
||||
root_dir=self.bdist_dir,
|
||||
)
|
||||
# create an exe containing the zip-file
|
||||
self.create_exe(arcname, fullname, self.bitmap)
|
||||
if self.distribution.has_ext_modules():
|
||||
pyversion = get_python_version()
|
||||
else:
|
||||
pyversion = 'any'
|
||||
self.distribution.dist_files.append(('bdist_wininst', pyversion,
|
||||
self.get_installer_filename(fullname)))
|
||||
self.distribution.dist_files.append((
|
||||
'bdist_wininst', pyversion,
|
||||
self.get_installer_filename(fullname),
|
||||
))
|
||||
# remove the zip-file again
|
||||
log.debug("removing temporary file '%s'", arcname)
|
||||
os.remove(arcname)
|
||||
|
|
@ -207,7 +256,7 @@ class bdist_wininst(Command):
|
|||
metadata = self.distribution.metadata
|
||||
|
||||
# Write the [metadata] section.
|
||||
lines.append("[metadata]")
|
||||
lines.append('[metadata]')
|
||||
|
||||
# 'info' will be displayed in the installer's dialog box,
|
||||
# describing the items to be installed.
|
||||
|
|
@ -215,37 +264,41 @@ class bdist_wininst(Command):
|
|||
|
||||
# Escape newline characters
|
||||
def escape(s):
|
||||
return s.replace("\n", "\\n")
|
||||
return s.replace('\n', '\\n')
|
||||
|
||||
for name in ["author", "author_email", "description", "maintainer",
|
||||
"maintainer_email", "name", "url", "version"]:
|
||||
data = getattr(metadata, name, "")
|
||||
for name in [
|
||||
'author', 'author_email', 'description', 'maintainer',
|
||||
'maintainer_email', 'name', 'url', 'version',
|
||||
]:
|
||||
data = getattr(metadata, name, '')
|
||||
if data:
|
||||
info = info + ("\n %s: %s" % \
|
||||
(name.capitalize(), escape(data)))
|
||||
lines.append("%s=%s" % (name, escape(data)))
|
||||
info = info + (
|
||||
'\n %s: %s' %
|
||||
(name.capitalize(), escape(data))
|
||||
)
|
||||
lines.append('{}={}'.format(name, escape(data)))
|
||||
|
||||
# The [setup] section contains entries controlling
|
||||
# the installer runtime.
|
||||
lines.append("\n[Setup]")
|
||||
lines.append('\n[Setup]')
|
||||
if self.install_script:
|
||||
lines.append("install_script=%s" % self.install_script)
|
||||
lines.append("info=%s" % escape(info))
|
||||
lines.append("target_compile=%d" % (not self.no_target_compile))
|
||||
lines.append("target_optimize=%d" % (not self.no_target_optimize))
|
||||
lines.append('install_script=%s' % self.install_script)
|
||||
lines.append('info=%s' % escape(info))
|
||||
lines.append('target_compile=%d' % (not self.no_target_compile))
|
||||
lines.append('target_optimize=%d' % (not self.no_target_optimize))
|
||||
if self.target_version:
|
||||
lines.append("target_version=%s" % self.target_version)
|
||||
lines.append('target_version=%s' % self.target_version)
|
||||
if self.user_access_control:
|
||||
lines.append("user_access_control=%s" % self.user_access_control)
|
||||
lines.append('user_access_control=%s' % self.user_access_control)
|
||||
|
||||
title = self.title or self.distribution.get_fullname()
|
||||
lines.append("title=%s" % escape(title))
|
||||
lines.append('title=%s' % escape(title))
|
||||
import time
|
||||
import distutils
|
||||
build_info = "Built %s with distutils-%s" % \
|
||||
build_info = 'Built %s with distutils-%s' % \
|
||||
(time.ctime(time.time()), distutils.__version__)
|
||||
lines.append("build_info=%s" % build_info)
|
||||
return "\n".join(lines)
|
||||
lines.append('build_info=%s' % build_info)
|
||||
return '\n'.join(lines)
|
||||
|
||||
def create_exe(self, arcname, fullname, bitmap=None):
|
||||
import struct
|
||||
|
|
@ -255,37 +308,39 @@ class bdist_wininst(Command):
|
|||
cfgdata = self.get_inidata()
|
||||
|
||||
installer_name = self.get_installer_filename(fullname)
|
||||
self.announce("creating %s" % installer_name)
|
||||
self.announce('creating %s' % installer_name)
|
||||
|
||||
if bitmap:
|
||||
with open(bitmap, "rb") as f:
|
||||
with open(bitmap, 'rb') as f:
|
||||
bitmapdata = f.read()
|
||||
bitmaplen = len(bitmapdata)
|
||||
else:
|
||||
bitmaplen = 0
|
||||
|
||||
with open(installer_name, "wb") as file:
|
||||
with open(installer_name, 'wb') as file:
|
||||
file.write(self.get_exe_bytes())
|
||||
if bitmap:
|
||||
file.write(bitmapdata)
|
||||
|
||||
# Convert cfgdata from unicode to ascii, mbcs encoded
|
||||
if isinstance(cfgdata, str):
|
||||
cfgdata = cfgdata.encode("mbcs")
|
||||
cfgdata = cfgdata.encode('mbcs')
|
||||
|
||||
# Append the pre-install script
|
||||
cfgdata = cfgdata + b"\0"
|
||||
cfgdata = cfgdata + b'\0'
|
||||
if self.pre_install_script:
|
||||
# We need to normalize newlines, so we open in text mode and
|
||||
# convert back to bytes. "latin-1" simply avoids any possible
|
||||
# failures.
|
||||
with open(self.pre_install_script, "r",
|
||||
encoding="latin-1") as script:
|
||||
script_data = script.read().encode("latin-1")
|
||||
cfgdata = cfgdata + script_data + b"\n\0"
|
||||
with open(
|
||||
self.pre_install_script,
|
||||
encoding='latin-1',
|
||||
) as script:
|
||||
script_data = script.read().encode('latin-1')
|
||||
cfgdata = cfgdata + script_data + b'\n\0'
|
||||
else:
|
||||
# empty pre-install script
|
||||
cfgdata = cfgdata + b"\0"
|
||||
cfgdata = cfgdata + b'\0'
|
||||
file.write(cfgdata)
|
||||
|
||||
# The 'magic number' 0x1234567B is used to make sure that the
|
||||
|
|
@ -293,13 +348,14 @@ class bdist_wininst(Command):
|
|||
# expects. If the layout changes, increment that number, make
|
||||
# the corresponding changes to the wininst.exe sources, and
|
||||
# recompile them.
|
||||
header = struct.pack("<iii",
|
||||
0x1234567B, # tag
|
||||
len(cfgdata), # length
|
||||
bitmaplen, # number of bytes in bitmap
|
||||
)
|
||||
header = struct.pack(
|
||||
'<iii',
|
||||
0x1234567B, # tag
|
||||
len(cfgdata), # length
|
||||
bitmaplen, # number of bytes in bitmap
|
||||
)
|
||||
file.write(header)
|
||||
with open(arcname, "rb") as f:
|
||||
with open(arcname, 'rb') as f:
|
||||
file.write(f.read())
|
||||
|
||||
def get_installer_filename(self, fullname):
|
||||
|
|
@ -307,12 +363,16 @@ class bdist_wininst(Command):
|
|||
if self.target_version:
|
||||
# if we create an installer for a specific python version,
|
||||
# it's better to include this in the name
|
||||
installer_name = os.path.join(self.dist_dir,
|
||||
"%s.%s-py%s.exe" %
|
||||
(fullname, self.plat_name, self.target_version))
|
||||
installer_name = os.path.join(
|
||||
self.dist_dir,
|
||||
'%s.%s-py%s.exe' %
|
||||
(fullname, self.plat_name, self.target_version),
|
||||
)
|
||||
else:
|
||||
installer_name = os.path.join(self.dist_dir,
|
||||
"%s.%s.exe" % (fullname, self.plat_name))
|
||||
installer_name = os.path.join(
|
||||
self.dist_dir,
|
||||
'{}.{}.exe'.format(fullname, self.plat_name),
|
||||
)
|
||||
return installer_name
|
||||
|
||||
def get_exe_bytes(self):
|
||||
|
|
@ -330,15 +390,15 @@ class bdist_wininst(Command):
|
|||
# use what we use
|
||||
# string compares seem wrong, but are what sysconfig.py itself uses
|
||||
if self.target_version and self.target_version < cur_version:
|
||||
if self.target_version < "2.4":
|
||||
if self.target_version < '2.4':
|
||||
bv = '6.0'
|
||||
elif self.target_version == "2.4":
|
||||
elif self.target_version == '2.4':
|
||||
bv = '7.1'
|
||||
elif self.target_version == "2.5":
|
||||
elif self.target_version == '2.5':
|
||||
bv = '8.0'
|
||||
elif self.target_version <= "3.2":
|
||||
elif self.target_version <= '3.2':
|
||||
bv = '9.0'
|
||||
elif self.target_version <= "3.4":
|
||||
elif self.target_version <= '3.4':
|
||||
bv = '10.0'
|
||||
else:
|
||||
bv = '14.0'
|
||||
|
|
@ -355,7 +415,6 @@ class bdist_wininst(Command):
|
|||
major = CRT_ASSEMBLY_VERSION.partition('.')[0]
|
||||
bv = major + '.0'
|
||||
|
||||
|
||||
# wininst-x.y.exe is in the same directory as this file
|
||||
directory = os.path.dirname(__file__)
|
||||
# we must use a wininst-x.y.exe built with the same C compiler
|
||||
|
|
@ -369,8 +428,8 @@ class bdist_wininst(Command):
|
|||
else:
|
||||
sfix = ''
|
||||
|
||||
filename = os.path.join(directory, "wininst-%s%s.exe" % (bv, sfix))
|
||||
f = open(filename, "rb")
|
||||
filename = os.path.join(directory, 'wininst-{}{}.exe'.format(bv, sfix))
|
||||
f = open(filename, 'rb')
|
||||
try:
|
||||
return f.read()
|
||||
finally:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
"""distutils.command.build
|
||||
|
||||
Implements the Distutils 'build' command."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import sys, os
|
||||
from distutils.core import Command
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.util import get_platform
|
||||
|
|
@ -15,43 +18,69 @@ def show_compilers():
|
|||
|
||||
class build(Command):
|
||||
|
||||
description = "build everything needed to install"
|
||||
description = 'build everything needed to install'
|
||||
|
||||
user_options = [
|
||||
('build-base=', 'b',
|
||||
"base directory for build library"),
|
||||
('build-purelib=', None,
|
||||
"build directory for platform-neutral distributions"),
|
||||
('build-platlib=', None,
|
||||
"build directory for platform-specific distributions"),
|
||||
('build-lib=', None,
|
||||
"build directory for all distribution (defaults to either " +
|
||||
"build-purelib or build-platlib"),
|
||||
('build-scripts=', None,
|
||||
"build directory for scripts"),
|
||||
('build-temp=', 't',
|
||||
"temporary build directory"),
|
||||
('plat-name=', 'p',
|
||||
"platform name to build for, if supported "
|
||||
"(default: %s)" % get_platform()),
|
||||
('compiler=', 'c',
|
||||
"specify the compiler type"),
|
||||
('parallel=', 'j',
|
||||
"number of parallel build jobs"),
|
||||
('debug', 'g',
|
||||
"compile extensions and libraries with debugging information"),
|
||||
('force', 'f',
|
||||
"forcibly build everything (ignore file timestamps)"),
|
||||
('executable=', 'e',
|
||||
"specify final destination interpreter path (build.py)"),
|
||||
]
|
||||
(
|
||||
'build-base=', 'b',
|
||||
'base directory for build library',
|
||||
),
|
||||
(
|
||||
'build-purelib=', None,
|
||||
'build directory for platform-neutral distributions',
|
||||
),
|
||||
(
|
||||
'build-platlib=', None,
|
||||
'build directory for platform-specific distributions',
|
||||
),
|
||||
(
|
||||
'build-lib=', None,
|
||||
'build directory for all distribution (defaults to either ' +
|
||||
'build-purelib or build-platlib',
|
||||
),
|
||||
(
|
||||
'build-scripts=', None,
|
||||
'build directory for scripts',
|
||||
),
|
||||
(
|
||||
'build-temp=', 't',
|
||||
'temporary build directory',
|
||||
),
|
||||
(
|
||||
'plat-name=', 'p',
|
||||
'platform name to build for, if supported '
|
||||
'(default: %s)' % get_platform(),
|
||||
),
|
||||
(
|
||||
'compiler=', 'c',
|
||||
'specify the compiler type',
|
||||
),
|
||||
(
|
||||
'parallel=', 'j',
|
||||
'number of parallel build jobs',
|
||||
),
|
||||
(
|
||||
'debug', 'g',
|
||||
'compile extensions and libraries with debugging information',
|
||||
),
|
||||
(
|
||||
'force', 'f',
|
||||
'forcibly build everything (ignore file timestamps)',
|
||||
),
|
||||
(
|
||||
'executable=', 'e',
|
||||
'specify final destination interpreter path (build.py)',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['debug', 'force']
|
||||
|
||||
help_options = [
|
||||
('help-compiler', None,
|
||||
"list available compilers", show_compilers),
|
||||
]
|
||||
(
|
||||
'help-compiler', None,
|
||||
'list available compilers', show_compilers,
|
||||
),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.build_base = 'build'
|
||||
|
|
@ -78,10 +107,11 @@ class build(Command):
|
|||
# other platforms.
|
||||
if os.name != 'nt':
|
||||
raise DistutilsOptionError(
|
||||
"--plat-name only supported on Windows (try "
|
||||
"using './configure --help' on your platform)")
|
||||
'--plat-name only supported on Windows (try '
|
||||
"using './configure --help' on your platform)",
|
||||
)
|
||||
|
||||
plat_specifier = ".%s-%d.%d" % (self.plat_name, *sys.version_info[:2])
|
||||
plat_specifier = '.%s-%d.%d' % (self.plat_name, *sys.version_info[:2])
|
||||
|
||||
# Make it so Python 2.x and Python 2.x with --with-pydebug don't
|
||||
# share the same build directories. Doing so confuses the build
|
||||
|
|
@ -95,8 +125,10 @@ class build(Command):
|
|||
if self.build_purelib is None:
|
||||
self.build_purelib = os.path.join(self.build_base, 'lib')
|
||||
if self.build_platlib is None:
|
||||
self.build_platlib = os.path.join(self.build_base,
|
||||
'lib' + plat_specifier)
|
||||
self.build_platlib = os.path.join(
|
||||
self.build_base,
|
||||
'lib' + plat_specifier,
|
||||
)
|
||||
|
||||
# 'build_lib' is the actual directory that we will use for this
|
||||
# particular module distribution -- if user didn't supply it, pick
|
||||
|
|
@ -110,11 +142,15 @@ class build(Command):
|
|||
# 'build_temp' -- temporary directory for compiler turds,
|
||||
# "build/temp.<plat>"
|
||||
if self.build_temp is None:
|
||||
self.build_temp = os.path.join(self.build_base,
|
||||
'temp' + plat_specifier)
|
||||
self.build_temp = os.path.join(
|
||||
self.build_base,
|
||||
'temp' + plat_specifier,
|
||||
)
|
||||
if self.build_scripts is None:
|
||||
self.build_scripts = os.path.join(self.build_base,
|
||||
'scripts-%d.%d' % sys.version_info[:2])
|
||||
self.build_scripts = os.path.join(
|
||||
self.build_base,
|
||||
'scripts-%d.%d' % sys.version_info[:2],
|
||||
)
|
||||
|
||||
if self.executable is None and sys.executable:
|
||||
self.executable = os.path.normpath(sys.executable)
|
||||
|
|
@ -123,7 +159,7 @@ class build(Command):
|
|||
try:
|
||||
self.parallel = int(self.parallel)
|
||||
except ValueError:
|
||||
raise DistutilsOptionError("parallel should be an integer")
|
||||
raise DistutilsOptionError('parallel should be an integer')
|
||||
|
||||
def run(self):
|
||||
# Run all relevant sub-commands. This will be some subset of:
|
||||
|
|
@ -134,7 +170,6 @@ class build(Command):
|
|||
for cmd_name in self.get_sub_commands():
|
||||
self.run_command(cmd_name)
|
||||
|
||||
|
||||
# -- Predicates for the sub-command list ---------------------------
|
||||
|
||||
def has_pure_modules(self):
|
||||
|
|
@ -149,9 +184,9 @@ class build(Command):
|
|||
def has_scripts(self):
|
||||
return self.distribution.has_scripts()
|
||||
|
||||
|
||||
sub_commands = [('build_py', has_pure_modules),
|
||||
('build_clib', has_c_libraries),
|
||||
('build_ext', has_ext_modules),
|
||||
('build_scripts', has_scripts),
|
||||
]
|
||||
sub_commands = [
|
||||
('build_py', has_pure_modules),
|
||||
('build_clib', has_c_libraries),
|
||||
('build_ext', has_ext_modules),
|
||||
('build_scripts', has_scripts),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
Implements the Distutils 'build_clib' command, to build a C/C++ library
|
||||
that is included in the module distribution and needed by an extension
|
||||
module."""
|
||||
|
||||
|
||||
# XXX this module has *lots* of code ripped-off quite transparently from
|
||||
# build_ext.py -- not surprisingly really, as the work required to build
|
||||
# a static library from a collection of C source files is not really all
|
||||
|
|
@ -13,12 +11,15 @@ module."""
|
|||
# necessary refactoring to account for the overlap in code between the
|
||||
# two modules, mainly because a number of subtle details changed in the
|
||||
# cut 'n paste. Sigh.
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
from distutils.sysconfig import customize_compiler
|
||||
from distutils import log
|
||||
|
||||
|
||||
def show_compilers():
|
||||
from distutils.ccompiler import show_compilers
|
||||
|
|
@ -27,27 +28,39 @@ def show_compilers():
|
|||
|
||||
class build_clib(Command):
|
||||
|
||||
description = "build C/C++ libraries used by Python extensions"
|
||||
description = 'build C/C++ libraries used by Python extensions'
|
||||
|
||||
user_options = [
|
||||
('build-clib=', 'b',
|
||||
"directory to build C/C++ libraries to"),
|
||||
('build-temp=', 't',
|
||||
"directory to put temporary build by-products"),
|
||||
('debug', 'g',
|
||||
"compile with debugging information"),
|
||||
('force', 'f',
|
||||
"forcibly build everything (ignore file timestamps)"),
|
||||
('compiler=', 'c',
|
||||
"specify the compiler type"),
|
||||
]
|
||||
(
|
||||
'build-clib=', 'b',
|
||||
'directory to build C/C++ libraries to',
|
||||
),
|
||||
(
|
||||
'build-temp=', 't',
|
||||
'directory to put temporary build by-products',
|
||||
),
|
||||
(
|
||||
'debug', 'g',
|
||||
'compile with debugging information',
|
||||
),
|
||||
(
|
||||
'force', 'f',
|
||||
'forcibly build everything (ignore file timestamps)',
|
||||
),
|
||||
(
|
||||
'compiler=', 'c',
|
||||
'specify the compiler type',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['debug', 'force']
|
||||
|
||||
help_options = [
|
||||
('help-compiler', None,
|
||||
"list available compilers", show_compilers),
|
||||
]
|
||||
(
|
||||
'help-compiler', None,
|
||||
'list available compilers', show_compilers,
|
||||
),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.build_clib = None
|
||||
|
|
@ -64,19 +77,20 @@ class build_clib(Command):
|
|||
self.force = 0
|
||||
self.compiler = None
|
||||
|
||||
|
||||
def finalize_options(self):
|
||||
# This might be confusing: both build-clib and build-temp default
|
||||
# to build-temp as defined by the "build" command. This is because
|
||||
# I think that C libraries are really just temporary build
|
||||
# by-products, at least from the point of view of building Python
|
||||
# extensions -- but I want to keep my options open.
|
||||
self.set_undefined_options('build',
|
||||
('build_temp', 'build_clib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('compiler', 'compiler'),
|
||||
('debug', 'debug'),
|
||||
('force', 'force'))
|
||||
self.set_undefined_options(
|
||||
'build',
|
||||
('build_temp', 'build_clib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('compiler', 'compiler'),
|
||||
('debug', 'debug'),
|
||||
('force', 'force'),
|
||||
)
|
||||
|
||||
self.libraries = self.distribution.libraries
|
||||
if self.libraries:
|
||||
|
|
@ -90,23 +104,24 @@ class build_clib(Command):
|
|||
# XXX same as for build_ext -- what about 'self.define' and
|
||||
# 'self.undef' ?
|
||||
|
||||
|
||||
def run(self):
|
||||
if not self.libraries:
|
||||
return
|
||||
|
||||
# Yech -- this is cut 'n pasted from build_ext.py!
|
||||
from distutils.ccompiler import new_compiler
|
||||
self.compiler = new_compiler(compiler=self.compiler,
|
||||
dry_run=self.dry_run,
|
||||
force=self.force)
|
||||
self.compiler = new_compiler(
|
||||
compiler=self.compiler,
|
||||
dry_run=self.dry_run,
|
||||
force=self.force,
|
||||
)
|
||||
customize_compiler(self.compiler)
|
||||
|
||||
if self.include_dirs is not None:
|
||||
self.compiler.set_include_dirs(self.include_dirs)
|
||||
if self.define is not None:
|
||||
# 'define' option is a list of (name,value) tuples
|
||||
for (name,value) in self.define:
|
||||
for (name, value) in self.define:
|
||||
self.compiler.define_macro(name, value)
|
||||
if self.undef is not None:
|
||||
for macro in self.undef:
|
||||
|
|
@ -114,7 +129,6 @@ class build_clib(Command):
|
|||
|
||||
self.build_libraries(self.libraries)
|
||||
|
||||
|
||||
def check_library_list(self, libraries):
|
||||
"""Ensure that the list of libraries is valid.
|
||||
|
||||
|
|
@ -127,29 +141,34 @@ class build_clib(Command):
|
|||
"""
|
||||
if not isinstance(libraries, list):
|
||||
raise DistutilsSetupError(
|
||||
"'libraries' option must be a list of tuples")
|
||||
"'libraries' option must be a list of tuples",
|
||||
)
|
||||
|
||||
for lib in libraries:
|
||||
if not isinstance(lib, tuple) and len(lib) != 2:
|
||||
raise DistutilsSetupError(
|
||||
"each element of 'libraries' must a 2-tuple")
|
||||
"each element of 'libraries' must a 2-tuple",
|
||||
)
|
||||
|
||||
name, build_info = lib
|
||||
|
||||
if not isinstance(name, str):
|
||||
raise DistutilsSetupError(
|
||||
"first element of each tuple in 'libraries' "
|
||||
"must be a string (the library name)")
|
||||
"first element of each tuple in 'libraries' "
|
||||
'must be a string (the library name)',
|
||||
)
|
||||
|
||||
if '/' in name or (os.sep != '/' and os.sep in name):
|
||||
raise DistutilsSetupError("bad library name '%s': "
|
||||
"may not contain directory separators" % lib[0])
|
||||
raise DistutilsSetupError(
|
||||
"bad library name '%s': "
|
||||
'may not contain directory separators' % lib[0],
|
||||
)
|
||||
|
||||
if not isinstance(build_info, dict):
|
||||
raise DistutilsSetupError(
|
||||
"second element of each tuple in 'libraries' "
|
||||
"must be a dictionary (build info)")
|
||||
|
||||
"second element of each tuple in 'libraries' "
|
||||
'must be a dictionary (build info)',
|
||||
)
|
||||
|
||||
def get_library_names(self):
|
||||
# Assume the library list is valid -- 'check_library_list()' is
|
||||
|
|
@ -162,7 +181,6 @@ class build_clib(Command):
|
|||
lib_names.append(lib_name)
|
||||
return lib_names
|
||||
|
||||
|
||||
def get_source_files(self):
|
||||
self.check_library_list(self.libraries)
|
||||
filenames = []
|
||||
|
|
@ -170,22 +188,23 @@ class build_clib(Command):
|
|||
sources = build_info.get('sources')
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % lib_name)
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
'a list of source filenames' % lib_name,
|
||||
)
|
||||
|
||||
filenames.extend(sources)
|
||||
return filenames
|
||||
|
||||
|
||||
def build_libraries(self, libraries):
|
||||
for (lib_name, build_info) in libraries:
|
||||
sources = build_info.get('sources')
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % lib_name)
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
'a list of source filenames' % lib_name,
|
||||
)
|
||||
sources = list(sources)
|
||||
|
||||
log.info("building '%s' library", lib_name)
|
||||
|
|
@ -195,15 +214,19 @@ class build_clib(Command):
|
|||
# files in a temporary build directory.)
|
||||
macros = build_info.get('macros')
|
||||
include_dirs = build_info.get('include_dirs')
|
||||
objects = self.compiler.compile(sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=include_dirs,
|
||||
debug=self.debug)
|
||||
objects = self.compiler.compile(
|
||||
sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=include_dirs,
|
||||
debug=self.debug,
|
||||
)
|
||||
|
||||
# Now "link" the object files together into a static library.
|
||||
# (On Unix at least, this isn't really linking -- it just
|
||||
# builds an archive. Whatever.)
|
||||
self.compiler.create_static_lib(objects, lib_name,
|
||||
output_dir=self.build_clib,
|
||||
debug=self.debug)
|
||||
self.compiler.create_static_lib(
|
||||
objects, lib_name,
|
||||
output_dir=self.build_clib,
|
||||
debug=self.debug,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,37 +3,39 @@
|
|||
Implements the Distutils 'build_ext' command, for building extension
|
||||
modules (currently limited to C extensions, should accommodate C++
|
||||
extensions ASAP)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
from distutils.sysconfig import customize_compiler, get_python_version
|
||||
from distutils.sysconfig import get_config_h_filename
|
||||
from distutils.dep_util import newer_group
|
||||
from distutils.extension import Extension
|
||||
from distutils.util import get_platform
|
||||
from distutils import log
|
||||
from . import py37compat
|
||||
|
||||
from site import USER_BASE
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.dep_util import newer_group
|
||||
from distutils.errors import *
|
||||
from distutils.extension import Extension
|
||||
from distutils.sysconfig import customize_compiler
|
||||
from distutils.sysconfig import get_config_h_filename
|
||||
from distutils.sysconfig import get_python_version
|
||||
from distutils.util import get_platform
|
||||
|
||||
from . import py37compat
|
||||
|
||||
# An extension name is just a dot-separated list of Python NAMEs (ie.
|
||||
# the same as a fully-qualified module name).
|
||||
extension_name_re = re.compile \
|
||||
(r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
|
||||
extension_name_re = re.compile(r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
|
||||
|
||||
|
||||
def show_compilers ():
|
||||
def show_compilers():
|
||||
from distutils.ccompiler import show_compilers
|
||||
show_compilers()
|
||||
|
||||
|
||||
class build_ext(Command):
|
||||
|
||||
description = "build C/C++ extensions (compile/link to build directory)"
|
||||
description = 'build C/C++ extensions (compile/link to build directory)'
|
||||
|
||||
# XXX thoughts on how to deal with complex command-line options like
|
||||
# these, i.e. how to make it so fancy_getopt can suck them off the
|
||||
|
|
@ -55,54 +57,94 @@ class build_ext(Command):
|
|||
|
||||
sep_by = " (separated by '%s')" % os.pathsep
|
||||
user_options = [
|
||||
('build-lib=', 'b',
|
||||
"directory for compiled extension modules"),
|
||||
('build-temp=', 't',
|
||||
"directory for temporary files (build by-products)"),
|
||||
('plat-name=', 'p',
|
||||
"platform name to cross-compile for, if supported "
|
||||
"(default: %s)" % get_platform()),
|
||||
('inplace', 'i',
|
||||
"ignore build-lib and put compiled extensions into the source " +
|
||||
"directory alongside your pure Python modules"),
|
||||
('include-dirs=', 'I',
|
||||
"list of directories to search for header files" + sep_by),
|
||||
('define=', 'D',
|
||||
"C preprocessor macros to define"),
|
||||
('undef=', 'U',
|
||||
"C preprocessor macros to undefine"),
|
||||
('libraries=', 'l',
|
||||
"external C libraries to link with"),
|
||||
('library-dirs=', 'L',
|
||||
"directories to search for external C libraries" + sep_by),
|
||||
('rpath=', 'R',
|
||||
"directories to search for shared C libraries at runtime"),
|
||||
('link-objects=', 'O',
|
||||
"extra explicit link objects to include in the link"),
|
||||
('debug', 'g',
|
||||
"compile/link with debugging information"),
|
||||
('force', 'f',
|
||||
"forcibly build everything (ignore file timestamps)"),
|
||||
('compiler=', 'c',
|
||||
"specify the compiler type"),
|
||||
('parallel=', 'j',
|
||||
"number of parallel build jobs"),
|
||||
('swig-cpp', None,
|
||||
"make SWIG create C++ files (default is C)"),
|
||||
('swig-opts=', None,
|
||||
"list of SWIG command line options"),
|
||||
('swig=', None,
|
||||
"path to the SWIG executable"),
|
||||
('user', None,
|
||||
"add user include, library and rpath")
|
||||
]
|
||||
(
|
||||
'build-lib=', 'b',
|
||||
'directory for compiled extension modules',
|
||||
),
|
||||
(
|
||||
'build-temp=', 't',
|
||||
'directory for temporary files (build by-products)',
|
||||
),
|
||||
(
|
||||
'plat-name=', 'p',
|
||||
'platform name to cross-compile for, if supported '
|
||||
'(default: %s)' % get_platform(),
|
||||
),
|
||||
(
|
||||
'inplace', 'i',
|
||||
'ignore build-lib and put compiled extensions into the source ' +
|
||||
'directory alongside your pure Python modules',
|
||||
),
|
||||
(
|
||||
'include-dirs=', 'I',
|
||||
'list of directories to search for header files' + sep_by,
|
||||
),
|
||||
(
|
||||
'define=', 'D',
|
||||
'C preprocessor macros to define',
|
||||
),
|
||||
(
|
||||
'undef=', 'U',
|
||||
'C preprocessor macros to undefine',
|
||||
),
|
||||
(
|
||||
'libraries=', 'l',
|
||||
'external C libraries to link with',
|
||||
),
|
||||
(
|
||||
'library-dirs=', 'L',
|
||||
'directories to search for external C libraries' + sep_by,
|
||||
),
|
||||
(
|
||||
'rpath=', 'R',
|
||||
'directories to search for shared C libraries at runtime',
|
||||
),
|
||||
(
|
||||
'link-objects=', 'O',
|
||||
'extra explicit link objects to include in the link',
|
||||
),
|
||||
(
|
||||
'debug', 'g',
|
||||
'compile/link with debugging information',
|
||||
),
|
||||
(
|
||||
'force', 'f',
|
||||
'forcibly build everything (ignore file timestamps)',
|
||||
),
|
||||
(
|
||||
'compiler=', 'c',
|
||||
'specify the compiler type',
|
||||
),
|
||||
(
|
||||
'parallel=', 'j',
|
||||
'number of parallel build jobs',
|
||||
),
|
||||
(
|
||||
'swig-cpp', None,
|
||||
'make SWIG create C++ files (default is C)',
|
||||
),
|
||||
(
|
||||
'swig-opts=', None,
|
||||
'list of SWIG command line options',
|
||||
),
|
||||
(
|
||||
'swig=', None,
|
||||
'path to the SWIG executable',
|
||||
),
|
||||
(
|
||||
'user', None,
|
||||
'add user include, library and rpath',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['inplace', 'debug', 'force', 'swig-cpp', 'user']
|
||||
|
||||
help_options = [
|
||||
('help-compiler', None,
|
||||
"list available compilers", show_compilers),
|
||||
]
|
||||
(
|
||||
'help-compiler', None,
|
||||
'list available compilers', show_compilers,
|
||||
),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.extensions = None
|
||||
|
|
@ -131,15 +173,16 @@ class build_ext(Command):
|
|||
def finalize_options(self):
|
||||
from distutils import sysconfig
|
||||
|
||||
self.set_undefined_options('build',
|
||||
('build_lib', 'build_lib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('compiler', 'compiler'),
|
||||
('debug', 'debug'),
|
||||
('force', 'force'),
|
||||
('parallel', 'parallel'),
|
||||
('plat_name', 'plat_name'),
|
||||
)
|
||||
self.set_undefined_options(
|
||||
'build',
|
||||
('build_lib', 'build_lib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('compiler', 'compiler'),
|
||||
('debug', 'debug'),
|
||||
('force', 'force'),
|
||||
('parallel', 'parallel'),
|
||||
('plat_name', 'plat_name'),
|
||||
)
|
||||
|
||||
if self.package is None:
|
||||
self.package = self.distribution.ext_package
|
||||
|
|
@ -165,7 +208,8 @@ class build_ext(Command):
|
|||
self.include_dirs.extend(py_include.split(os.path.pathsep))
|
||||
if plat_py_include != py_include:
|
||||
self.include_dirs.extend(
|
||||
plat_py_include.split(os.path.pathsep))
|
||||
plat_py_include.split(os.path.pathsep),
|
||||
)
|
||||
|
||||
self.ensure_string_list('libraries')
|
||||
self.ensure_string_list('link_objects')
|
||||
|
|
@ -195,9 +239,9 @@ class build_ext(Command):
|
|||
if sys.base_exec_prefix != sys.prefix: # Issue 16116
|
||||
self.library_dirs.append(os.path.join(sys.base_exec_prefix, 'libs'))
|
||||
if self.debug:
|
||||
self.build_temp = os.path.join(self.build_temp, "Debug")
|
||||
self.build_temp = os.path.join(self.build_temp, 'Debug')
|
||||
else:
|
||||
self.build_temp = os.path.join(self.build_temp, "Release")
|
||||
self.build_temp = os.path.join(self.build_temp, 'Release')
|
||||
|
||||
# Append the source distribution include and library directories,
|
||||
# this allows distutils on windows to work in the source tree
|
||||
|
|
@ -222,9 +266,13 @@ class build_ext(Command):
|
|||
if sys.platform[:6] == 'cygwin':
|
||||
if not sysconfig.python_build:
|
||||
# building third party extensions
|
||||
self.library_dirs.append(os.path.join(sys.prefix, "lib",
|
||||
"python" + get_python_version(),
|
||||
"config"))
|
||||
self.library_dirs.append(
|
||||
os.path.join(
|
||||
sys.prefix, 'lib',
|
||||
'python' + get_python_version(),
|
||||
'config',
|
||||
),
|
||||
)
|
||||
else:
|
||||
# building python standard extensions
|
||||
self.library_dirs.append('.')
|
||||
|
|
@ -262,8 +310,8 @@ class build_ext(Command):
|
|||
|
||||
# Finally add the user include and library directories if requested
|
||||
if self.user:
|
||||
user_include = os.path.join(USER_BASE, "include")
|
||||
user_lib = os.path.join(USER_BASE, "lib")
|
||||
user_include = os.path.join(USER_BASE, 'include')
|
||||
user_lib = os.path.join(USER_BASE, 'lib')
|
||||
if os.path.isdir(user_include):
|
||||
self.include_dirs.append(user_include)
|
||||
if os.path.isdir(user_lib):
|
||||
|
|
@ -274,7 +322,7 @@ class build_ext(Command):
|
|||
try:
|
||||
self.parallel = int(self.parallel)
|
||||
except ValueError:
|
||||
raise DistutilsOptionError("parallel should be an integer")
|
||||
raise DistutilsOptionError('parallel should be an integer')
|
||||
|
||||
def run(self):
|
||||
from distutils.ccompiler import new_compiler
|
||||
|
|
@ -304,10 +352,12 @@ class build_ext(Command):
|
|||
|
||||
# Setup the CCompiler object that we'll use to do all the
|
||||
# compiling and linking
|
||||
self.compiler = new_compiler(compiler=self.compiler,
|
||||
verbose=self.verbose,
|
||||
dry_run=self.dry_run,
|
||||
force=self.force)
|
||||
self.compiler = new_compiler(
|
||||
compiler=self.compiler,
|
||||
verbose=self.verbose,
|
||||
dry_run=self.dry_run,
|
||||
force=self.force,
|
||||
)
|
||||
customize_compiler(self.compiler)
|
||||
# If we are cross-compiling, init the compiler now (if we are not
|
||||
# cross-compiling, init would not hurt, but people may rely on
|
||||
|
|
@ -352,34 +402,42 @@ class build_ext(Command):
|
|||
"""
|
||||
if not isinstance(extensions, list):
|
||||
raise DistutilsSetupError(
|
||||
"'ext_modules' option must be a list of Extension instances")
|
||||
"'ext_modules' option must be a list of Extension instances",
|
||||
)
|
||||
|
||||
for i, ext in enumerate(extensions):
|
||||
if isinstance(ext, Extension):
|
||||
continue # OK! (assume type-checking done
|
||||
# by Extension constructor)
|
||||
# by Extension constructor)
|
||||
|
||||
if not isinstance(ext, tuple) or len(ext) != 2:
|
||||
raise DistutilsSetupError(
|
||||
"each element of 'ext_modules' option must be an "
|
||||
"Extension instance or 2-tuple")
|
||||
"each element of 'ext_modules' option must be an "
|
||||
'Extension instance or 2-tuple',
|
||||
)
|
||||
|
||||
ext_name, build_info = ext
|
||||
|
||||
log.warn("old-style (ext_name, build_info) tuple found in "
|
||||
"ext_modules for extension '%s' "
|
||||
"-- please convert to Extension instance", ext_name)
|
||||
log.warn(
|
||||
'old-style (ext_name, build_info) tuple found in '
|
||||
"ext_modules for extension '%s' "
|
||||
'-- please convert to Extension instance', ext_name,
|
||||
)
|
||||
|
||||
if not (isinstance(ext_name, str) and
|
||||
extension_name_re.match(ext_name)):
|
||||
if not (
|
||||
isinstance(ext_name, str) and
|
||||
extension_name_re.match(ext_name)
|
||||
):
|
||||
raise DistutilsSetupError(
|
||||
"first element of each tuple in 'ext_modules' "
|
||||
"must be the extension name (a string)")
|
||||
"first element of each tuple in 'ext_modules' "
|
||||
'must be the extension name (a string)',
|
||||
)
|
||||
|
||||
if not isinstance(build_info, dict):
|
||||
raise DistutilsSetupError(
|
||||
"second element of each tuple in 'ext_modules' "
|
||||
"must be a dictionary (build info)")
|
||||
"second element of each tuple in 'ext_modules' "
|
||||
'must be a dictionary (build info)',
|
||||
)
|
||||
|
||||
# OK, the (ext_name, build_info) dict is type-safe: convert it
|
||||
# to an Extension instance.
|
||||
|
|
@ -387,9 +445,11 @@ class build_ext(Command):
|
|||
|
||||
# Easy stuff: one-to-one mapping from dict elements to
|
||||
# instance attributes.
|
||||
for key in ('include_dirs', 'library_dirs', 'libraries',
|
||||
'extra_objects', 'extra_compile_args',
|
||||
'extra_link_args'):
|
||||
for key in (
|
||||
'include_dirs', 'library_dirs', 'libraries',
|
||||
'extra_objects', 'extra_compile_args',
|
||||
'extra_link_args',
|
||||
):
|
||||
val = build_info.get(key)
|
||||
if val is not None:
|
||||
setattr(ext, key, val)
|
||||
|
|
@ -397,8 +457,10 @@ class build_ext(Command):
|
|||
# Medium-easy stuff: same syntax/semantics, different names.
|
||||
ext.runtime_library_dirs = build_info.get('rpath')
|
||||
if 'def_file' in build_info:
|
||||
log.warn("'def_file' element of build info dict "
|
||||
"no longer supported")
|
||||
log.warn(
|
||||
"'def_file' element of build info dict "
|
||||
'no longer supported',
|
||||
)
|
||||
|
||||
# Non-trivial stuff: 'macros' split into 'define_macros'
|
||||
# and 'undef_macros'.
|
||||
|
|
@ -409,8 +471,9 @@ class build_ext(Command):
|
|||
for macro in macros:
|
||||
if not (isinstance(macro, tuple) and len(macro) in (1, 2)):
|
||||
raise DistutilsSetupError(
|
||||
"'macros' element of build info dict "
|
||||
"must be 1- or 2-tuple")
|
||||
"'macros' element of build info dict "
|
||||
'must be 1- or 2-tuple',
|
||||
)
|
||||
if len(macro) == 1:
|
||||
ext.undef_macros.append(macro[0])
|
||||
elif len(macro) == 2:
|
||||
|
|
@ -463,8 +526,10 @@ class build_ext(Command):
|
|||
return
|
||||
|
||||
with ThreadPoolExecutor(max_workers=workers) as executor:
|
||||
futures = [executor.submit(self.build_extension, ext)
|
||||
for ext in self.extensions]
|
||||
futures = [
|
||||
executor.submit(self.build_extension, ext)
|
||||
for ext in self.extensions
|
||||
]
|
||||
for ext, fut in zip(self.extensions, futures):
|
||||
with self._filter_build_errors(ext):
|
||||
fut.result()
|
||||
|
|
@ -481,16 +546,19 @@ class build_ext(Command):
|
|||
except (CCompilerError, DistutilsError, CompileError) as e:
|
||||
if not ext.optional:
|
||||
raise
|
||||
self.warn('building extension "%s" failed: %s' %
|
||||
(ext.name, e))
|
||||
self.warn(
|
||||
'building extension "%s" failed: %s' %
|
||||
(ext.name, e),
|
||||
)
|
||||
|
||||
def build_extension(self, ext):
|
||||
sources = ext.sources
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'ext_modules' option (extension '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % ext.name)
|
||||
"in 'ext_modules' option (extension '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
'a list of source filenames' % ext.name,
|
||||
)
|
||||
# sort to make the resulting .so file build reproducible
|
||||
sources = sorted(sources)
|
||||
|
||||
|
|
@ -527,13 +595,15 @@ class build_ext(Command):
|
|||
for undef in ext.undef_macros:
|
||||
macros.append((undef,))
|
||||
|
||||
objects = self.compiler.compile(sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=ext.include_dirs,
|
||||
debug=self.debug,
|
||||
extra_postargs=extra_args,
|
||||
depends=ext.depends)
|
||||
objects = self.compiler.compile(
|
||||
sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=ext.include_dirs,
|
||||
debug=self.debug,
|
||||
extra_postargs=extra_args,
|
||||
depends=ext.depends,
|
||||
)
|
||||
|
||||
# XXX outdated variable, kept here in case third-part code
|
||||
# needs it.
|
||||
|
|
@ -558,7 +628,8 @@ class build_ext(Command):
|
|||
export_symbols=self.get_export_symbols(ext),
|
||||
debug=self.debug,
|
||||
build_temp=self.build_temp,
|
||||
target_lang=language)
|
||||
target_lang=language,
|
||||
)
|
||||
|
||||
def swig_sources(self, sources, extension):
|
||||
"""Walk the list of source files in 'sources', looking for SWIG
|
||||
|
|
@ -576,7 +647,7 @@ class build_ext(Command):
|
|||
# the temp dir.
|
||||
|
||||
if self.swig_cpp:
|
||||
log.warn("--swig-cpp is deprecated - use --swig-opts=-c++")
|
||||
log.warn('--swig-cpp is deprecated - use --swig-opts=-c++')
|
||||
|
||||
if self.swig_cpp or ('-c++' in self.swig_opts) or \
|
||||
('-c++' in extension.swig_opts):
|
||||
|
|
@ -586,7 +657,7 @@ class build_ext(Command):
|
|||
|
||||
for source in sources:
|
||||
(base, ext) = os.path.splitext(source)
|
||||
if ext == ".i": # SWIG interface file
|
||||
if ext == '.i': # SWIG interface file
|
||||
new_sources.append(base + '_wrap' + target_ext)
|
||||
swig_sources.append(source)
|
||||
swig_targets[source] = new_sources[-1]
|
||||
|
|
@ -597,10 +668,10 @@ class build_ext(Command):
|
|||
return new_sources
|
||||
|
||||
swig = self.swig or self.find_swig()
|
||||
swig_cmd = [swig, "-python"]
|
||||
swig_cmd = [swig, '-python']
|
||||
swig_cmd.extend(self.swig_opts)
|
||||
if self.swig_cpp:
|
||||
swig_cmd.append("-c++")
|
||||
swig_cmd.append('-c++')
|
||||
|
||||
# Do not override commandline arguments
|
||||
if not self.swig_opts:
|
||||
|
|
@ -609,8 +680,8 @@ class build_ext(Command):
|
|||
|
||||
for source in swig_sources:
|
||||
target = swig_targets[source]
|
||||
log.info("swigging %s to %s", source, target)
|
||||
self.spawn(swig_cmd + ["-o", target, source])
|
||||
log.info('swigging %s to %s', source, target)
|
||||
self.spawn(swig_cmd + ['-o', target, source])
|
||||
|
||||
return new_sources
|
||||
|
||||
|
|
@ -619,22 +690,23 @@ class build_ext(Command):
|
|||
just "swig" -- it should be in the PATH. Tries a bit harder on
|
||||
Windows.
|
||||
"""
|
||||
if os.name == "posix":
|
||||
return "swig"
|
||||
elif os.name == "nt":
|
||||
if os.name == 'posix':
|
||||
return 'swig'
|
||||
elif os.name == 'nt':
|
||||
# Look for SWIG in its standard installation directory on
|
||||
# Windows (or so I presume!). If we find it there, great;
|
||||
# if not, act like Unix and assume it's in the PATH.
|
||||
for vers in ("1.3", "1.2", "1.1"):
|
||||
fn = os.path.join("c:\\swig%s" % vers, "swig.exe")
|
||||
for vers in ('1.3', '1.2', '1.1'):
|
||||
fn = os.path.join('c:\\swig%s' % vers, 'swig.exe')
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
else:
|
||||
return "swig.exe"
|
||||
return 'swig.exe'
|
||||
else:
|
||||
raise DistutilsPlatformError(
|
||||
"I don't know how to find (much less run) SWIG "
|
||||
"on platform '%s'" % os.name)
|
||||
"I don't know how to find (much less run) SWIG "
|
||||
"on platform '%s'" % os.name,
|
||||
)
|
||||
|
||||
# -- Name generators -----------------------------------------------
|
||||
# (extension names, filenames, whatever)
|
||||
|
|
@ -652,7 +724,7 @@ class build_ext(Command):
|
|||
# no further work needed
|
||||
# returning :
|
||||
# build_dir/package/path/filename
|
||||
filename = os.path.join(*modpath[:-1]+[filename])
|
||||
filename = os.path.join(*modpath[:-1] + [filename])
|
||||
return os.path.join(self.build_lib, filename)
|
||||
|
||||
# the inplace option requires to find the package directory
|
||||
|
|
@ -698,9 +770,9 @@ class build_ext(Command):
|
|||
except UnicodeEncodeError:
|
||||
suffix = 'U_' + name.encode('punycode').replace(b'-', b'_').decode('ascii')
|
||||
else:
|
||||
suffix = "_" + name
|
||||
suffix = '_' + name
|
||||
|
||||
initfunc_name = "PyInit" + suffix
|
||||
initfunc_name = 'PyInit' + suffix
|
||||
if initfunc_name not in ext.export_symbols:
|
||||
ext.export_symbols.append(initfunc_name)
|
||||
return ext.export_symbols
|
||||
|
|
@ -715,14 +787,16 @@ class build_ext(Command):
|
|||
# pyconfig.h that MSVC groks. The other Windows compilers all seem
|
||||
# to need it mentioned explicitly, though, so that's what we do.
|
||||
# Append '_d' to the python import library on debug builds.
|
||||
if sys.platform == "win32":
|
||||
if sys.platform == 'win32':
|
||||
from distutils._msvccompiler import MSVCCompiler
|
||||
if not isinstance(self.compiler, MSVCCompiler):
|
||||
template = "python%d%d"
|
||||
template = 'python%d%d'
|
||||
if self.debug:
|
||||
template = template + '_d'
|
||||
pythonlib = (template %
|
||||
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
|
||||
pythonlib = (
|
||||
template %
|
||||
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)
|
||||
)
|
||||
# don't extend ext.libraries, it may be shared with other
|
||||
# extensions, it is a reference to the original list
|
||||
return ext.libraries + [pythonlib]
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
"""distutils.command.build_py
|
||||
|
||||
Implements the Distutils 'build_py' command."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import importlib.util
|
||||
import sys
|
||||
import glob
|
||||
import importlib.util
|
||||
import os
|
||||
import sys
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.errors import *
|
||||
from distutils.util import convert_path
|
||||
from distutils import log
|
||||
|
||||
|
||||
class build_py (Command):
|
||||
|
||||
|
|
@ -18,16 +20,18 @@ class build_py (Command):
|
|||
|
||||
user_options = [
|
||||
('build-lib=', 'd', "directory to \"build\" (copy) to"),
|
||||
('compile', 'c', "compile .py to .pyc"),
|
||||
('compile', 'c', 'compile .py to .pyc'),
|
||||
('no-compile', None, "don't compile .py files [default]"),
|
||||
('optimize=', 'O',
|
||||
"also compile with optimization: -O1 for \"python -O\", "
|
||||
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
|
||||
('force', 'f', "forcibly build everything (ignore file timestamps)"),
|
||||
]
|
||||
(
|
||||
'optimize=', 'O',
|
||||
"also compile with optimization: -O1 for \"python -O\", "
|
||||
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]",
|
||||
),
|
||||
('force', 'f', 'forcibly build everything (ignore file timestamps)'),
|
||||
]
|
||||
|
||||
boolean_options = ['compile', 'force']
|
||||
negative_opt = {'no-compile' : 'compile'}
|
||||
negative_opt = {'no-compile': 'compile'}
|
||||
|
||||
def initialize_options(self):
|
||||
self.build_lib = None
|
||||
|
|
@ -40,9 +44,11 @@ class build_py (Command):
|
|||
self.force = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('build',
|
||||
('build_lib', 'build_lib'),
|
||||
('force', 'force'))
|
||||
self.set_undefined_options(
|
||||
'build',
|
||||
('build_lib', 'build_lib'),
|
||||
('force', 'force'),
|
||||
)
|
||||
|
||||
# Get the distribution options that are aliases for build_py
|
||||
# options -- list of packages and list of modules.
|
||||
|
|
@ -62,7 +68,7 @@ class build_py (Command):
|
|||
self.optimize = int(self.optimize)
|
||||
assert 0 <= self.optimize <= 2
|
||||
except (ValueError, AssertionError):
|
||||
raise DistutilsOptionError("optimize must be 0, 1, or 2")
|
||||
raise DistutilsOptionError('optimize must be 0, 1, or 2')
|
||||
|
||||
def run(self):
|
||||
# XXX copy_file by default preserves atime and mtime. IMHO this is
|
||||
|
|
@ -109,26 +115,30 @@ class build_py (Command):
|
|||
# Length of path to strip from found files
|
||||
plen = 0
|
||||
if src_dir:
|
||||
plen = len(src_dir)+1
|
||||
plen = len(src_dir) + 1
|
||||
|
||||
# Strip directory from globbed filenames
|
||||
filenames = [
|
||||
file[plen:] for file in self.find_data_files(package, src_dir)
|
||||
]
|
||||
]
|
||||
data.append((package, src_dir, build_dir, filenames))
|
||||
return data
|
||||
|
||||
def find_data_files(self, package, src_dir):
|
||||
"""Return filenames for package's data files in 'src_dir'"""
|
||||
globs = (self.package_data.get('', [])
|
||||
+ self.package_data.get(package, []))
|
||||
globs = (
|
||||
self.package_data.get('', []) +
|
||||
self.package_data.get(package, [])
|
||||
)
|
||||
files = []
|
||||
for pattern in globs:
|
||||
# Each pattern has to be converted to a platform-specific path
|
||||
filelist = glob.glob(os.path.join(glob.escape(src_dir), convert_path(pattern)))
|
||||
# Files that match more than one pattern are only added once
|
||||
files.extend([fn for fn in filelist if fn not in files
|
||||
and os.path.isfile(fn)])
|
||||
files.extend([
|
||||
fn for fn in filelist if fn not in files and
|
||||
os.path.isfile(fn)
|
||||
])
|
||||
return files
|
||||
|
||||
def build_package_data(self):
|
||||
|
|
@ -138,8 +148,10 @@ class build_py (Command):
|
|||
for filename in filenames:
|
||||
target = os.path.join(build_dir, filename)
|
||||
self.mkpath(os.path.dirname(target))
|
||||
self.copy_file(os.path.join(src_dir, filename), target,
|
||||
preserve_mode=False)
|
||||
self.copy_file(
|
||||
os.path.join(src_dir, filename), target,
|
||||
preserve_mode=False,
|
||||
)
|
||||
|
||||
def get_package_dir(self, package):
|
||||
"""Return the directory, relative to the top of the source
|
||||
|
|
@ -185,23 +197,29 @@ class build_py (Command):
|
|||
# assume exists. Also, os.path.exists and isdir don't know about
|
||||
# my "empty string means current dir" convention, so we have to
|
||||
# circumvent them.
|
||||
if package_dir != "":
|
||||
if package_dir != '':
|
||||
if not os.path.exists(package_dir):
|
||||
raise DistutilsFileError(
|
||||
"package directory '%s' does not exist" % package_dir)
|
||||
"package directory '%s' does not exist" % package_dir,
|
||||
)
|
||||
if not os.path.isdir(package_dir):
|
||||
raise DistutilsFileError(
|
||||
"supposed package directory '%s' exists, "
|
||||
"but is not a directory" % package_dir)
|
||||
"supposed package directory '%s' exists, "
|
||||
'but is not a directory' % package_dir,
|
||||
)
|
||||
|
||||
# Require __init__.py for all but the "root package"
|
||||
if package:
|
||||
init_py = os.path.join(package_dir, "__init__.py")
|
||||
init_py = os.path.join(package_dir, '__init__.py')
|
||||
if os.path.isfile(init_py):
|
||||
return init_py
|
||||
else:
|
||||
log.warn(("package init file '%s' not found " +
|
||||
"(or not a regular file)"), init_py)
|
||||
log.warn(
|
||||
(
|
||||
"package init file '%s' not found " +
|
||||
'(or not a regular file)'
|
||||
), init_py,
|
||||
)
|
||||
|
||||
# Either not in a package at all (__init__.py not expected), or
|
||||
# __init__.py doesn't exist -- so don't return the filename.
|
||||
|
|
@ -209,14 +227,14 @@ class build_py (Command):
|
|||
|
||||
def check_module(self, module, module_file):
|
||||
if not os.path.isfile(module_file):
|
||||
log.warn("file %s (for module %s) not found", module_file, module)
|
||||
log.warn('file %s (for module %s) not found', module_file, module)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def find_package_modules(self, package, package_dir):
|
||||
self.check_package(package, package_dir)
|
||||
module_files = glob.glob(os.path.join(glob.escape(package_dir), "*.py"))
|
||||
module_files = glob.glob(os.path.join(glob.escape(package_dir), '*.py'))
|
||||
modules = []
|
||||
setup_script = os.path.abspath(self.distribution.script_name)
|
||||
|
||||
|
|
@ -226,7 +244,7 @@ class build_py (Command):
|
|||
module = os.path.splitext(os.path.basename(f))[0]
|
||||
modules.append((package, module, f))
|
||||
else:
|
||||
self.debug_print("excluding %s" % setup_script)
|
||||
self.debug_print('excluding %s' % setup_script)
|
||||
return modules
|
||||
|
||||
def find_modules(self):
|
||||
|
|
@ -268,12 +286,12 @@ class build_py (Command):
|
|||
init_py = self.check_package(package, package_dir)
|
||||
packages[package] = (package_dir, 1)
|
||||
if init_py:
|
||||
modules.append((package, "__init__", init_py))
|
||||
modules.append((package, '__init__', init_py))
|
||||
|
||||
# XXX perhaps we should also check for just .pyc files
|
||||
# (so greedy closed-source bastards can distribute Python
|
||||
# modules too)
|
||||
module_file = os.path.join(package_dir, module_base + ".py")
|
||||
module_file = os.path.join(package_dir, module_base + '.py')
|
||||
if not self.check_module(module, module_file):
|
||||
continue
|
||||
|
||||
|
|
@ -301,7 +319,7 @@ class build_py (Command):
|
|||
return [module[-1] for module in self.find_all_modules()]
|
||||
|
||||
def get_module_outfile(self, build_dir, package, module):
|
||||
outfile_path = [build_dir] + list(package) + [module + ".py"]
|
||||
outfile_path = [build_dir] + list(package) + [module + '.py']
|
||||
return os.path.join(*outfile_path)
|
||||
|
||||
def get_outputs(self, include_bytecode=1):
|
||||
|
|
@ -313,17 +331,23 @@ class build_py (Command):
|
|||
outputs.append(filename)
|
||||
if include_bytecode:
|
||||
if self.compile:
|
||||
outputs.append(importlib.util.cache_from_source(
|
||||
filename, optimization=''))
|
||||
outputs.append(
|
||||
importlib.util.cache_from_source(
|
||||
filename, optimization='',
|
||||
),
|
||||
)
|
||||
if self.optimize > 0:
|
||||
outputs.append(importlib.util.cache_from_source(
|
||||
filename, optimization=self.optimize))
|
||||
outputs.append(
|
||||
importlib.util.cache_from_source(
|
||||
filename, optimization=self.optimize,
|
||||
),
|
||||
)
|
||||
|
||||
outputs += [
|
||||
os.path.join(build_dir, filename)
|
||||
for package, src_dir, build_dir, filenames in self.data_files
|
||||
for filename in filenames
|
||||
]
|
||||
]
|
||||
|
||||
return outputs
|
||||
|
||||
|
|
@ -332,7 +356,8 @@ class build_py (Command):
|
|||
package = package.split('.')
|
||||
elif not isinstance(package, (list, tuple)):
|
||||
raise TypeError(
|
||||
"'package' must be a string (dot-separated), list, or tuple")
|
||||
"'package' must be a string (dot-separated), list, or tuple",
|
||||
)
|
||||
|
||||
# Now put the module source file into the "build" area -- this is
|
||||
# easy, we just copy it somewhere under self.build_lib (the build
|
||||
|
|
@ -385,8 +410,12 @@ class build_py (Command):
|
|||
# method of the "install_lib" command, except for the determination
|
||||
# of the 'prefix' string. Hmmm.
|
||||
if self.compile:
|
||||
byte_compile(files, optimize=0,
|
||||
force=self.force, prefix=prefix, dry_run=self.dry_run)
|
||||
byte_compile(
|
||||
files, optimize=0,
|
||||
force=self.force, prefix=prefix, dry_run=self.dry_run,
|
||||
)
|
||||
if self.optimize > 0:
|
||||
byte_compile(files, optimize=self.optimize,
|
||||
force=self.force, prefix=prefix, dry_run=self.dry_run)
|
||||
byte_compile(
|
||||
files, optimize=self.optimize,
|
||||
force=self.force, prefix=prefix, dry_run=self.dry_run,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,32 +1,35 @@
|
|||
"""distutils.command.build_scripts
|
||||
|
||||
Implements the Distutils 'build_scripts' command."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os, re
|
||||
import os
|
||||
import re
|
||||
import tokenize
|
||||
from stat import ST_MODE
|
||||
|
||||
from distutils import log
|
||||
from distutils import sysconfig
|
||||
from distutils.core import Command
|
||||
from distutils.dep_util import newer
|
||||
from distutils.util import convert_path
|
||||
from distutils import log
|
||||
import tokenize
|
||||
|
||||
# check if Python is called on the first line with this expression
|
||||
first_line_re = re.compile(b'^#!.*python[0-9.]*([ \t].*)?$')
|
||||
|
||||
|
||||
class build_scripts(Command):
|
||||
|
||||
description = "\"build\" scripts (copy and fixup #! line)"
|
||||
|
||||
user_options = [
|
||||
('build-dir=', 'd', "directory to \"build\" (copy) to"),
|
||||
('force', 'f', "forcibly build everything (ignore file timestamps"),
|
||||
('executable=', 'e', "specify final destination interpreter path"),
|
||||
]
|
||||
('force', 'f', 'forcibly build everything (ignore file timestamps'),
|
||||
('executable=', 'e', 'specify final destination interpreter path'),
|
||||
]
|
||||
|
||||
boolean_options = ['force']
|
||||
|
||||
|
||||
def initialize_options(self):
|
||||
self.build_dir = None
|
||||
self.scripts = None
|
||||
|
|
@ -35,10 +38,12 @@ class build_scripts(Command):
|
|||
self.outfiles = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('build',
|
||||
('build_scripts', 'build_dir'),
|
||||
('force', 'force'),
|
||||
('executable', 'executable'))
|
||||
self.set_undefined_options(
|
||||
'build',
|
||||
('build_scripts', 'build_dir'),
|
||||
('force', 'force'),
|
||||
('executable', 'executable'),
|
||||
)
|
||||
self.scripts = self.distribution.scripts
|
||||
|
||||
def get_source_files(self):
|
||||
|
|
@ -49,7 +54,6 @@ class build_scripts(Command):
|
|||
return
|
||||
self.copy_scripts()
|
||||
|
||||
|
||||
def copy_scripts(self):
|
||||
r"""Copy each script listed in 'self.scripts'; if it's marked as a
|
||||
Python script in the Unix way (first line matches 'first_line_re',
|
||||
|
|
@ -66,14 +70,14 @@ class build_scripts(Command):
|
|||
outfiles.append(outfile)
|
||||
|
||||
if not self.force and not newer(script, outfile):
|
||||
log.debug("not copying %s (up-to-date)", script)
|
||||
log.debug('not copying %s (up-to-date)', script)
|
||||
continue
|
||||
|
||||
# Always open the file, but ignore failures in dry-run mode --
|
||||
# that way, we'll get accurate feedback if we can read the
|
||||
# script.
|
||||
try:
|
||||
f = open(script, "rb")
|
||||
f = open(script, 'rb')
|
||||
except OSError:
|
||||
if not self.dry_run:
|
||||
raise
|
||||
|
|
@ -83,7 +87,7 @@ class build_scripts(Command):
|
|||
f.seek(0)
|
||||
first_line = f.readline()
|
||||
if not first_line:
|
||||
self.warn("%s is an empty file (skipping)" % script)
|
||||
self.warn('%s is an empty file (skipping)' % script)
|
||||
continue
|
||||
|
||||
match = first_line_re.match(first_line)
|
||||
|
|
@ -92,19 +96,24 @@ class build_scripts(Command):
|
|||
post_interp = match.group(1) or b''
|
||||
|
||||
if adjust:
|
||||
log.info("copying and adjusting %s -> %s", script,
|
||||
self.build_dir)
|
||||
log.info(
|
||||
'copying and adjusting %s -> %s', script,
|
||||
self.build_dir,
|
||||
)
|
||||
updated_files.append(outfile)
|
||||
if not self.dry_run:
|
||||
if not sysconfig.python_build:
|
||||
executable = self.executable
|
||||
else:
|
||||
executable = os.path.join(
|
||||
sysconfig.get_config_var("BINDIR"),
|
||||
"python%s%s" % (sysconfig.get_config_var("VERSION"),
|
||||
sysconfig.get_config_var("EXE")))
|
||||
sysconfig.get_config_var('BINDIR'),
|
||||
'python{}{}'.format(
|
||||
sysconfig.get_config_var('VERSION'),
|
||||
sysconfig.get_config_var('EXE'),
|
||||
),
|
||||
)
|
||||
executable = os.fsencode(executable)
|
||||
shebang = b"#!" + executable + post_interp + b"\n"
|
||||
shebang = b'#!' + executable + post_interp + b'\n'
|
||||
# Python parser starts to read a script using UTF-8 until
|
||||
# it gets a #coding:xxx cookie. The shebang has to be the
|
||||
# first line of a file, the #coding:xxx cookie cannot be
|
||||
|
|
@ -114,8 +123,9 @@ class build_scripts(Command):
|
|||
shebang.decode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
raise ValueError(
|
||||
"The shebang ({!r}) is not decodable "
|
||||
"from utf-8".format(shebang))
|
||||
'The shebang ({!r}) is not decodable '
|
||||
'from utf-8'.format(shebang),
|
||||
)
|
||||
# If the script is encoded to a custom encoding (use a
|
||||
# #coding:xxx cookie), the shebang has to be decodable from
|
||||
# the script encoding too.
|
||||
|
|
@ -123,10 +133,11 @@ class build_scripts(Command):
|
|||
shebang.decode(encoding)
|
||||
except UnicodeDecodeError:
|
||||
raise ValueError(
|
||||
"The shebang ({!r}) is not decodable "
|
||||
"from the script encoding ({})"
|
||||
.format(shebang, encoding))
|
||||
with open(outfile, "wb") as outf:
|
||||
'The shebang ({!r}) is not decodable '
|
||||
'from the script encoding ({})'
|
||||
.format(shebang, encoding),
|
||||
)
|
||||
with open(outfile, 'wb') as outf:
|
||||
outf.write(shebang)
|
||||
outf.writelines(f.readlines())
|
||||
if f:
|
||||
|
|
@ -140,13 +151,15 @@ class build_scripts(Command):
|
|||
if os.name == 'posix':
|
||||
for file in outfiles:
|
||||
if self.dry_run:
|
||||
log.info("changing mode of %s", file)
|
||||
log.info('changing mode of %s', file)
|
||||
else:
|
||||
oldmode = os.stat(file)[ST_MODE] & 0o7777
|
||||
newmode = (oldmode | 0o555) & 0o7777
|
||||
if newmode != oldmode:
|
||||
log.info("changing mode of %s from %o to %o",
|
||||
file, oldmode, newmode)
|
||||
log.info(
|
||||
'changing mode of %s from %o to %o',
|
||||
file, oldmode, newmode,
|
||||
)
|
||||
os.chmod(file, newmode)
|
||||
# XXX should we modify self.outfiles?
|
||||
return outfiles, updated_files
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
Implements the Distutils 'check' command.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils.errors import DistutilsSetupError
|
||||
|
||||
|
|
@ -14,17 +16,23 @@ try:
|
|||
|
||||
class SilentReporter(Reporter):
|
||||
|
||||
def __init__(self, source, report_level, halt_level, stream=None,
|
||||
debug=0, encoding='ascii', error_handler='replace'):
|
||||
def __init__(
|
||||
self, source, report_level, halt_level, stream=None,
|
||||
debug=0, encoding='ascii', error_handler='replace',
|
||||
):
|
||||
self.messages = []
|
||||
Reporter.__init__(self, source, report_level, halt_level, stream,
|
||||
debug, encoding, error_handler)
|
||||
Reporter.__init__(
|
||||
self, source, report_level, halt_level, stream,
|
||||
debug, encoding, error_handler,
|
||||
)
|
||||
|
||||
def system_message(self, level, message, *children, **kwargs):
|
||||
self.messages.append((level, message, children, kwargs))
|
||||
return nodes.system_message(message, level=level,
|
||||
type=self.levels[level],
|
||||
*children, **kwargs)
|
||||
return nodes.system_message(
|
||||
message, level=level,
|
||||
type=self.levels[level],
|
||||
*children, **kwargs,
|
||||
)
|
||||
|
||||
HAS_DOCUTILS = True
|
||||
except Exception:
|
||||
|
|
@ -32,16 +40,25 @@ except Exception:
|
|||
# indicate that docutils is not ported to Py3k.
|
||||
HAS_DOCUTILS = False
|
||||
|
||||
|
||||
class check(Command):
|
||||
"""This command checks the meta-data of the package.
|
||||
"""
|
||||
description = ("perform some checks on the package")
|
||||
user_options = [('metadata', 'm', 'Verify meta-data'),
|
||||
('restructuredtext', 'r',
|
||||
('Checks if long string meta-data syntax '
|
||||
'are reStructuredText-compliant')),
|
||||
('strict', 's',
|
||||
'Will exit with an error if a check fails')]
|
||||
description = ('perform some checks on the package')
|
||||
user_options = [
|
||||
('metadata', 'm', 'Verify meta-data'),
|
||||
(
|
||||
'restructuredtext', 'r',
|
||||
(
|
||||
'Checks if long string meta-data syntax '
|
||||
'are reStructuredText-compliant'
|
||||
),
|
||||
),
|
||||
(
|
||||
'strict', 's',
|
||||
'Will exit with an error if a check fails',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['metadata', 'restructuredtext', 'strict']
|
||||
|
||||
|
|
@ -95,19 +112,25 @@ class check(Command):
|
|||
missing.append(attr)
|
||||
|
||||
if missing:
|
||||
self.warn("missing required meta-data: %s" % ', '.join(missing))
|
||||
self.warn('missing required meta-data: %s' % ', '.join(missing))
|
||||
if metadata.author:
|
||||
if not metadata.author_email:
|
||||
self.warn("missing meta-data: if 'author' supplied, " +
|
||||
"'author_email' should be supplied too")
|
||||
self.warn(
|
||||
"missing meta-data: if 'author' supplied, " +
|
||||
"'author_email' should be supplied too",
|
||||
)
|
||||
elif metadata.maintainer:
|
||||
if not metadata.maintainer_email:
|
||||
self.warn("missing meta-data: if 'maintainer' supplied, " +
|
||||
"'maintainer_email' should be supplied too")
|
||||
self.warn(
|
||||
"missing meta-data: if 'maintainer' supplied, " +
|
||||
"'maintainer_email' should be supplied too",
|
||||
)
|
||||
else:
|
||||
self.warn("missing meta-data: either (author and author_email) " +
|
||||
"or (maintainer and maintainer_email) " +
|
||||
"should be supplied")
|
||||
self.warn(
|
||||
'missing meta-data: either (author and author_email) ' +
|
||||
'or (maintainer and maintainer_email) ' +
|
||||
'should be supplied',
|
||||
)
|
||||
|
||||
def check_restructuredtext(self):
|
||||
"""Checks if the long string fields are reST-compliant."""
|
||||
|
|
@ -117,7 +140,7 @@ class check(Command):
|
|||
if line is None:
|
||||
warning = warning[1]
|
||||
else:
|
||||
warning = '%s (line %s)' % (warning[1], line)
|
||||
warning = '{} (line {})'.format(warning[1], line)
|
||||
self.warn(warning)
|
||||
|
||||
def _check_rst_data(self, data):
|
||||
|
|
@ -129,13 +152,15 @@ class check(Command):
|
|||
settings.tab_width = 4
|
||||
settings.pep_references = None
|
||||
settings.rfc_references = None
|
||||
reporter = SilentReporter(source_path,
|
||||
settings.report_level,
|
||||
settings.halt_level,
|
||||
stream=settings.warning_stream,
|
||||
debug=settings.debug,
|
||||
encoding=settings.error_encoding,
|
||||
error_handler=settings.error_encoding_error_handler)
|
||||
reporter = SilentReporter(
|
||||
source_path,
|
||||
settings.report_level,
|
||||
settings.halt_level,
|
||||
stream=settings.warning_stream,
|
||||
debug=settings.debug,
|
||||
encoding=settings.error_encoding,
|
||||
error_handler=settings.error_encoding_error_handler,
|
||||
)
|
||||
|
||||
document = nodes.document(settings, reporter, source=source_path)
|
||||
document.note_source(source_path, -1)
|
||||
|
|
@ -143,6 +168,7 @@ class check(Command):
|
|||
parser.parse(data, document)
|
||||
except AttributeError as e:
|
||||
reporter.messages.append(
|
||||
(-1, 'Could not finish the parsing: %s.' % e, '', {}))
|
||||
(-1, 'Could not finish the parsing: %s.' % e, '', {}),
|
||||
)
|
||||
|
||||
return reporter.messages
|
||||
|
|
|
|||
|
|
@ -1,30 +1,44 @@
|
|||
"""distutils.command.clean
|
||||
|
||||
Implements the Distutils 'clean' command."""
|
||||
|
||||
# contributed by Bastian Kleineidam <calvin@cs.uni-sb.de>, added 2000-03-18
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.dir_util import remove_tree
|
||||
from distutils import log
|
||||
|
||||
|
||||
class clean(Command):
|
||||
|
||||
description = "clean up temporary files from 'build' command"
|
||||
user_options = [
|
||||
('build-base=', 'b',
|
||||
"base build directory (default: 'build.build-base')"),
|
||||
('build-lib=', None,
|
||||
"build directory for all modules (default: 'build.build-lib')"),
|
||||
('build-temp=', 't',
|
||||
"temporary build directory (default: 'build.build-temp')"),
|
||||
('build-scripts=', None,
|
||||
"build directory for scripts (default: 'build.build-scripts')"),
|
||||
('bdist-base=', None,
|
||||
"temporary directory for built distributions"),
|
||||
('all', 'a',
|
||||
"remove all build output, not just temporary by-products")
|
||||
(
|
||||
'build-base=', 'b',
|
||||
"base build directory (default: 'build.build-base')",
|
||||
),
|
||||
(
|
||||
'build-lib=', None,
|
||||
"build directory for all modules (default: 'build.build-lib')",
|
||||
),
|
||||
(
|
||||
'build-temp=', 't',
|
||||
"temporary build directory (default: 'build.build-temp')",
|
||||
),
|
||||
(
|
||||
'build-scripts=', None,
|
||||
"build directory for scripts (default: 'build.build-scripts')",
|
||||
),
|
||||
(
|
||||
'bdist-base=', None,
|
||||
'temporary directory for built distributions',
|
||||
),
|
||||
(
|
||||
'all', 'a',
|
||||
'remove all build output, not just temporary by-products',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['all']
|
||||
|
|
@ -38,13 +52,17 @@ class clean(Command):
|
|||
self.all = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('build',
|
||||
('build_base', 'build_base'),
|
||||
('build_lib', 'build_lib'),
|
||||
('build_scripts', 'build_scripts'),
|
||||
('build_temp', 'build_temp'))
|
||||
self.set_undefined_options('bdist',
|
||||
('bdist_base', 'bdist_base'))
|
||||
self.set_undefined_options(
|
||||
'build',
|
||||
('build_base', 'build_base'),
|
||||
('build_lib', 'build_lib'),
|
||||
('build_scripts', 'build_scripts'),
|
||||
('build_temp', 'build_temp'),
|
||||
)
|
||||
self.set_undefined_options(
|
||||
'bdist',
|
||||
('bdist_base', 'bdist_base'),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
# remove the build/temp.<plat> directory (unless it's already
|
||||
|
|
@ -52,19 +70,25 @@ class clean(Command):
|
|||
if os.path.exists(self.build_temp):
|
||||
remove_tree(self.build_temp, dry_run=self.dry_run)
|
||||
else:
|
||||
log.debug("'%s' does not exist -- can't clean it",
|
||||
self.build_temp)
|
||||
log.debug(
|
||||
"'%s' does not exist -- can't clean it",
|
||||
self.build_temp,
|
||||
)
|
||||
|
||||
if self.all:
|
||||
# remove build directories
|
||||
for directory in (self.build_lib,
|
||||
self.bdist_base,
|
||||
self.build_scripts):
|
||||
for directory in (
|
||||
self.build_lib,
|
||||
self.bdist_base,
|
||||
self.build_scripts,
|
||||
):
|
||||
if os.path.exists(directory):
|
||||
remove_tree(directory, dry_run=self.dry_run)
|
||||
else:
|
||||
log.warn("'%s' does not exist -- can't clean it",
|
||||
directory)
|
||||
log.warn(
|
||||
"'%s' does not exist -- can't clean it",
|
||||
directory,
|
||||
)
|
||||
|
||||
# just for the heck of it, try to remove the base build directory:
|
||||
# we might have emptied it right now, but if not we don't care
|
||||
|
|
|
|||
|
|
@ -8,42 +8,62 @@ list of standard commands. Also, this is a good place to put common
|
|||
configure-like tasks: "try to compile this C code", or "figure out where
|
||||
this header file lives".
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os, re
|
||||
import os
|
||||
import re
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.sysconfig import customize_compiler
|
||||
from distutils import log
|
||||
|
||||
LANG_EXT = {"c": ".c", "c++": ".cxx"}
|
||||
LANG_EXT = {'c': '.c', 'c++': '.cxx'}
|
||||
|
||||
|
||||
class config(Command):
|
||||
|
||||
description = "prepare to build"
|
||||
description = 'prepare to build'
|
||||
|
||||
user_options = [
|
||||
('compiler=', None,
|
||||
"specify the compiler type"),
|
||||
('cc=', None,
|
||||
"specify the compiler executable"),
|
||||
('include-dirs=', 'I',
|
||||
"list of directories to search for header files"),
|
||||
('define=', 'D',
|
||||
"C preprocessor macros to define"),
|
||||
('undef=', 'U',
|
||||
"C preprocessor macros to undefine"),
|
||||
('libraries=', 'l',
|
||||
"external C libraries to link with"),
|
||||
('library-dirs=', 'L',
|
||||
"directories to search for external C libraries"),
|
||||
|
||||
('noisy', None,
|
||||
"show every action (compile, link, run, ...) taken"),
|
||||
('dump-source', None,
|
||||
"dump generated source files before attempting to compile them"),
|
||||
]
|
||||
(
|
||||
'compiler=', None,
|
||||
'specify the compiler type',
|
||||
),
|
||||
(
|
||||
'cc=', None,
|
||||
'specify the compiler executable',
|
||||
),
|
||||
(
|
||||
'include-dirs=', 'I',
|
||||
'list of directories to search for header files',
|
||||
),
|
||||
(
|
||||
'define=', 'D',
|
||||
'C preprocessor macros to define',
|
||||
),
|
||||
(
|
||||
'undef=', 'U',
|
||||
'C preprocessor macros to undefine',
|
||||
),
|
||||
(
|
||||
'libraries=', 'l',
|
||||
'external C libraries to link with',
|
||||
),
|
||||
(
|
||||
'library-dirs=', 'L',
|
||||
'directories to search for external C libraries',
|
||||
),
|
||||
|
||||
(
|
||||
'noisy', None,
|
||||
'show every action (compile, link, run, ...) taken',
|
||||
),
|
||||
(
|
||||
'dump-source', None,
|
||||
'dump generated source files before attempting to compile them',
|
||||
),
|
||||
]
|
||||
|
||||
# The three standard command methods: since the "config" command
|
||||
# does nothing by default, these are empty.
|
||||
|
|
@ -94,8 +114,10 @@ class config(Command):
|
|||
# import.
|
||||
from distutils.ccompiler import CCompiler, new_compiler
|
||||
if not isinstance(self.compiler, CCompiler):
|
||||
self.compiler = new_compiler(compiler=self.compiler,
|
||||
dry_run=self.dry_run, force=1)
|
||||
self.compiler = new_compiler(
|
||||
compiler=self.compiler,
|
||||
dry_run=self.dry_run, force=1,
|
||||
)
|
||||
customize_compiler(self.compiler)
|
||||
if self.include_dirs:
|
||||
self.compiler.set_include_dirs(self.include_dirs)
|
||||
|
|
@ -105,20 +127,20 @@ class config(Command):
|
|||
self.compiler.set_library_dirs(self.library_dirs)
|
||||
|
||||
def _gen_temp_sourcefile(self, body, headers, lang):
|
||||
filename = "_configtest" + LANG_EXT[lang]
|
||||
with open(filename, "w") as file:
|
||||
filename = '_configtest' + LANG_EXT[lang]
|
||||
with open(filename, 'w') as file:
|
||||
if headers:
|
||||
for header in headers:
|
||||
file.write("#include <%s>\n" % header)
|
||||
file.write("\n")
|
||||
file.write('#include <%s>\n' % header)
|
||||
file.write('\n')
|
||||
file.write(body)
|
||||
if body[-1] != "\n":
|
||||
file.write("\n")
|
||||
if body[-1] != '\n':
|
||||
file.write('\n')
|
||||
return filename
|
||||
|
||||
def _preprocess(self, body, headers, include_dirs, lang):
|
||||
src = self._gen_temp_sourcefile(body, headers, lang)
|
||||
out = "_configtest.i"
|
||||
out = '_configtest.i'
|
||||
self.temp_files.extend([src, out])
|
||||
self.compiler.preprocess(src, out, include_dirs=include_dirs)
|
||||
return (src, out)
|
||||
|
|
@ -132,14 +154,18 @@ class config(Command):
|
|||
self.compiler.compile([src], include_dirs=include_dirs)
|
||||
return (src, obj)
|
||||
|
||||
def _link(self, body, headers, include_dirs, libraries, library_dirs,
|
||||
lang):
|
||||
def _link(
|
||||
self, body, headers, include_dirs, libraries, library_dirs,
|
||||
lang,
|
||||
):
|
||||
(src, obj) = self._compile(body, headers, include_dirs, lang)
|
||||
prog = os.path.splitext(os.path.basename(src))[0]
|
||||
self.compiler.link_executable([obj], prog,
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs,
|
||||
target_lang=lang)
|
||||
self.compiler.link_executable(
|
||||
[obj], prog,
|
||||
libraries=libraries,
|
||||
library_dirs=library_dirs,
|
||||
target_lang=lang,
|
||||
)
|
||||
|
||||
if self.compiler.exe_extension is not None:
|
||||
prog = prog + self.compiler.exe_extension
|
||||
|
|
@ -151,14 +177,13 @@ class config(Command):
|
|||
if not filenames:
|
||||
filenames = self.temp_files
|
||||
self.temp_files = []
|
||||
log.info("removing: %s", ' '.join(filenames))
|
||||
log.info('removing: %s', ' '.join(filenames))
|
||||
for filename in filenames:
|
||||
try:
|
||||
os.remove(filename)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
# XXX these ignore the dry-run flag: what to do, what to do? even if
|
||||
# you want a dry-run build, you still need some sort of configuration
|
||||
# info. My inclination is to make it up to the real config command to
|
||||
|
|
@ -169,7 +194,7 @@ class config(Command):
|
|||
|
||||
# XXX need access to the header search path and maybe default macros.
|
||||
|
||||
def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"):
|
||||
def try_cpp(self, body=None, headers=None, include_dirs=None, lang='c'):
|
||||
"""Construct a source file from 'body' (a string containing lines
|
||||
of C/C++ code) and 'headers' (a list of header files to include)
|
||||
and run it through the preprocessor. Return true if the
|
||||
|
|
@ -187,8 +212,10 @@ class config(Command):
|
|||
self._clean()
|
||||
return ok
|
||||
|
||||
def search_cpp(self, pattern, body=None, headers=None, include_dirs=None,
|
||||
lang="c"):
|
||||
def search_cpp(
|
||||
self, pattern, body=None, headers=None, include_dirs=None,
|
||||
lang='c',
|
||||
):
|
||||
"""Construct a source file (just like 'try_cpp()'), run it through
|
||||
the preprocessor, and return true if any line of the output matches
|
||||
'pattern'. 'pattern' should either be a compiled regex object or a
|
||||
|
|
@ -215,7 +242,7 @@ class config(Command):
|
|||
self._clean()
|
||||
return match
|
||||
|
||||
def try_compile(self, body, headers=None, include_dirs=None, lang="c"):
|
||||
def try_compile(self, body, headers=None, include_dirs=None, lang='c'):
|
||||
"""Try to compile a source file built from 'body' and 'headers'.
|
||||
Return true on success, false otherwise.
|
||||
"""
|
||||
|
|
@ -227,12 +254,14 @@ class config(Command):
|
|||
except CompileError:
|
||||
ok = False
|
||||
|
||||
log.info(ok and "success!" or "failure.")
|
||||
log.info(ok and 'success!' or 'failure.')
|
||||
self._clean()
|
||||
return ok
|
||||
|
||||
def try_link(self, body, headers=None, include_dirs=None, libraries=None,
|
||||
library_dirs=None, lang="c"):
|
||||
def try_link(
|
||||
self, body, headers=None, include_dirs=None, libraries=None,
|
||||
library_dirs=None, lang='c',
|
||||
):
|
||||
"""Try to compile and link a source file, built from 'body' and
|
||||
'headers', to executable form. Return true on success, false
|
||||
otherwise.
|
||||
|
|
@ -240,18 +269,22 @@ class config(Command):
|
|||
from distutils.ccompiler import CompileError, LinkError
|
||||
self._check_compiler()
|
||||
try:
|
||||
self._link(body, headers, include_dirs,
|
||||
libraries, library_dirs, lang)
|
||||
self._link(
|
||||
body, headers, include_dirs,
|
||||
libraries, library_dirs, lang,
|
||||
)
|
||||
ok = True
|
||||
except (CompileError, LinkError):
|
||||
ok = False
|
||||
|
||||
log.info(ok and "success!" or "failure.")
|
||||
log.info(ok and 'success!' or 'failure.')
|
||||
self._clean()
|
||||
return ok
|
||||
|
||||
def try_run(self, body, headers=None, include_dirs=None, libraries=None,
|
||||
library_dirs=None, lang="c"):
|
||||
def try_run(
|
||||
self, body, headers=None, include_dirs=None, libraries=None,
|
||||
library_dirs=None, lang='c',
|
||||
):
|
||||
"""Try to compile, link to an executable, and run a program
|
||||
built from 'body' and 'headers'. Return true on success, false
|
||||
otherwise.
|
||||
|
|
@ -259,24 +292,27 @@ class config(Command):
|
|||
from distutils.ccompiler import CompileError, LinkError
|
||||
self._check_compiler()
|
||||
try:
|
||||
src, obj, exe = self._link(body, headers, include_dirs,
|
||||
libraries, library_dirs, lang)
|
||||
src, obj, exe = self._link(
|
||||
body, headers, include_dirs,
|
||||
libraries, library_dirs, lang,
|
||||
)
|
||||
self.spawn([exe])
|
||||
ok = True
|
||||
except (CompileError, LinkError, DistutilsExecError):
|
||||
ok = False
|
||||
|
||||
log.info(ok and "success!" or "failure.")
|
||||
log.info(ok and 'success!' or 'failure.')
|
||||
self._clean()
|
||||
return ok
|
||||
|
||||
|
||||
# -- High-level methods --------------------------------------------
|
||||
# (these are the ones that are actually likely to be useful
|
||||
# when implementing a real-world config command!)
|
||||
|
||||
def check_func(self, func, headers=None, include_dirs=None,
|
||||
libraries=None, library_dirs=None, decl=0, call=0):
|
||||
def check_func(
|
||||
self, func, headers=None, include_dirs=None,
|
||||
libraries=None, library_dirs=None, decl=0, call=0,
|
||||
):
|
||||
"""Determine if function 'func' is available by constructing a
|
||||
source file that refers to 'func', and compiles and links it.
|
||||
If everything succeeds, returns true; otherwise returns false.
|
||||
|
|
@ -293,20 +329,24 @@ class config(Command):
|
|||
self._check_compiler()
|
||||
body = []
|
||||
if decl:
|
||||
body.append("int %s ();" % func)
|
||||
body.append("int main () {")
|
||||
body.append('int %s ();' % func)
|
||||
body.append('int main () {')
|
||||
if call:
|
||||
body.append(" %s();" % func)
|
||||
body.append(' %s();' % func)
|
||||
else:
|
||||
body.append(" %s;" % func)
|
||||
body.append("}")
|
||||
body = "\n".join(body) + "\n"
|
||||
body.append(' %s;' % func)
|
||||
body.append('}')
|
||||
body = '\n'.join(body) + '\n'
|
||||
|
||||
return self.try_link(body, headers, include_dirs,
|
||||
libraries, library_dirs)
|
||||
return self.try_link(
|
||||
body, headers, include_dirs,
|
||||
libraries, library_dirs,
|
||||
)
|
||||
|
||||
def check_lib(self, library, library_dirs=None, headers=None,
|
||||
include_dirs=None, other_libraries=[]):
|
||||
def check_lib(
|
||||
self, library, library_dirs=None, headers=None,
|
||||
include_dirs=None, other_libraries=[],
|
||||
):
|
||||
"""Determine if 'library' is available to be linked against,
|
||||
without actually checking that any particular symbols are provided
|
||||
by it. 'headers' will be used in constructing the source file to
|
||||
|
|
@ -316,17 +356,24 @@ class config(Command):
|
|||
has symbols that depend on other libraries.
|
||||
"""
|
||||
self._check_compiler()
|
||||
return self.try_link("int main (void) { }", headers, include_dirs,
|
||||
[library] + other_libraries, library_dirs)
|
||||
return self.try_link(
|
||||
'int main (void) { }', headers, include_dirs,
|
||||
[library] + other_libraries, library_dirs,
|
||||
)
|
||||
|
||||
def check_header(self, header, include_dirs=None, library_dirs=None,
|
||||
lang="c"):
|
||||
def check_header(
|
||||
self, header, include_dirs=None, library_dirs=None,
|
||||
lang='c',
|
||||
):
|
||||
"""Determine if the system header file named by 'header_file'
|
||||
exists and can be found by the preprocessor; return true if so,
|
||||
false otherwise.
|
||||
"""
|
||||
return self.try_cpp(body="/* No body */", headers=[header],
|
||||
include_dirs=include_dirs)
|
||||
return self.try_cpp(
|
||||
body='/* No body */', headers=[header],
|
||||
include_dirs=include_dirs,
|
||||
)
|
||||
|
||||
|
||||
def dump_file(filename, head=None):
|
||||
"""Dumps a file content into log.info.
|
||||
|
|
|
|||
|
|
@ -1,22 +1,24 @@
|
|||
"""distutils.command.install
|
||||
|
||||
Implements the Distutils 'install' command."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import sys
|
||||
from site import USER_BASE
|
||||
from site import USER_SITE
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.debug import DEBUG
|
||||
from distutils.sysconfig import get_config_vars
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
from distutils.file_util import write_file
|
||||
from distutils.util import convert_path, subst_vars, change_root
|
||||
from distutils.sysconfig import get_config_vars
|
||||
from distutils.util import change_root
|
||||
from distutils.util import convert_path
|
||||
from distutils.util import get_platform
|
||||
from distutils.errors import DistutilsOptionError
|
||||
|
||||
from site import USER_BASE
|
||||
from site import USER_SITE
|
||||
from distutils.util import subst_vars
|
||||
HAS_USER_SITE = True
|
||||
|
||||
WINDOWS_SCHEME = {
|
||||
|
|
@ -24,7 +26,7 @@ WINDOWS_SCHEME = {
|
|||
'platlib': '$base/Lib/site-packages',
|
||||
'headers': '$base/Include/$dist_name',
|
||||
'scripts': '$base/Scripts',
|
||||
'data' : '$base',
|
||||
'data': '$base',
|
||||
}
|
||||
|
||||
INSTALL_SCHEMES = {
|
||||
|
|
@ -33,31 +35,31 @@ INSTALL_SCHEMES = {
|
|||
'platlib': '$platbase/$platlibdir/python$py_version_short/site-packages',
|
||||
'headers': '$base/include/python$py_version_short$abiflags/$dist_name',
|
||||
'scripts': '$base/bin',
|
||||
'data' : '$base',
|
||||
},
|
||||
'data': '$base',
|
||||
},
|
||||
'unix_home': {
|
||||
'purelib': '$base/lib/python',
|
||||
'platlib': '$base/$platlibdir/python',
|
||||
'headers': '$base/include/python/$dist_name',
|
||||
'scripts': '$base/bin',
|
||||
'data' : '$base',
|
||||
},
|
||||
'data': '$base',
|
||||
},
|
||||
'nt': WINDOWS_SCHEME,
|
||||
'pypy': {
|
||||
'purelib': '$base/site-packages',
|
||||
'platlib': '$base/site-packages',
|
||||
'headers': '$base/include/$dist_name',
|
||||
'scripts': '$base/bin',
|
||||
'data' : '$base',
|
||||
},
|
||||
'data': '$base',
|
||||
},
|
||||
'pypy_nt': {
|
||||
'purelib': '$base/site-packages',
|
||||
'platlib': '$base/site-packages',
|
||||
'headers': '$base/include/$dist_name',
|
||||
'scripts': '$base/Scripts',
|
||||
'data' : '$base',
|
||||
},
|
||||
}
|
||||
'data': '$base',
|
||||
},
|
||||
}
|
||||
|
||||
# user site schemes
|
||||
if HAS_USER_SITE:
|
||||
|
|
@ -66,8 +68,8 @@ if HAS_USER_SITE:
|
|||
'platlib': '$usersite',
|
||||
'headers': '$userbase/Python$py_version_nodot/Include/$dist_name',
|
||||
'scripts': '$userbase/Python$py_version_nodot/Scripts',
|
||||
'data' : '$userbase',
|
||||
}
|
||||
'data': '$userbase',
|
||||
}
|
||||
|
||||
INSTALL_SCHEMES['unix_user'] = {
|
||||
'purelib': '$usersite',
|
||||
|
|
@ -75,8 +77,8 @@ if HAS_USER_SITE:
|
|||
'headers':
|
||||
'$userbase/include/python$py_version_short$abiflags/$dist_name',
|
||||
'scripts': '$userbase/bin',
|
||||
'data' : '$userbase',
|
||||
}
|
||||
'data': '$userbase',
|
||||
}
|
||||
|
||||
# The keys to an installation scheme; if any new types of files are to be
|
||||
# installed, be sure to add an entry to every installation scheme above,
|
||||
|
|
@ -86,56 +88,86 @@ SCHEME_KEYS = ('purelib', 'platlib', 'headers', 'scripts', 'data')
|
|||
|
||||
class install(Command):
|
||||
|
||||
description = "install everything from build directory"
|
||||
description = 'install everything from build directory'
|
||||
|
||||
user_options = [
|
||||
# Select installation scheme and set base director(y|ies)
|
||||
('prefix=', None,
|
||||
"installation prefix"),
|
||||
('exec-prefix=', None,
|
||||
"(Unix only) prefix for platform-specific files"),
|
||||
('home=', None,
|
||||
"(Unix only) home directory to install under"),
|
||||
(
|
||||
'prefix=', None,
|
||||
'installation prefix',
|
||||
),
|
||||
(
|
||||
'exec-prefix=', None,
|
||||
'(Unix only) prefix for platform-specific files',
|
||||
),
|
||||
(
|
||||
'home=', None,
|
||||
'(Unix only) home directory to install under',
|
||||
),
|
||||
|
||||
# Or, just set the base director(y|ies)
|
||||
('install-base=', None,
|
||||
"base installation directory (instead of --prefix or --home)"),
|
||||
('install-platbase=', None,
|
||||
"base installation directory for platform-specific files " +
|
||||
"(instead of --exec-prefix or --home)"),
|
||||
('root=', None,
|
||||
"install everything relative to this alternate root directory"),
|
||||
(
|
||||
'install-base=', None,
|
||||
'base installation directory (instead of --prefix or --home)',
|
||||
),
|
||||
(
|
||||
'install-platbase=', None,
|
||||
'base installation directory for platform-specific files ' +
|
||||
'(instead of --exec-prefix or --home)',
|
||||
),
|
||||
(
|
||||
'root=', None,
|
||||
'install everything relative to this alternate root directory',
|
||||
),
|
||||
|
||||
# Or, explicitly set the installation scheme
|
||||
('install-purelib=', None,
|
||||
"installation directory for pure Python module distributions"),
|
||||
('install-platlib=', None,
|
||||
"installation directory for non-pure module distributions"),
|
||||
('install-lib=', None,
|
||||
"installation directory for all module distributions " +
|
||||
"(overrides --install-purelib and --install-platlib)"),
|
||||
(
|
||||
'install-purelib=', None,
|
||||
'installation directory for pure Python module distributions',
|
||||
),
|
||||
(
|
||||
'install-platlib=', None,
|
||||
'installation directory for non-pure module distributions',
|
||||
),
|
||||
(
|
||||
'install-lib=', None,
|
||||
'installation directory for all module distributions ' +
|
||||
'(overrides --install-purelib and --install-platlib)',
|
||||
),
|
||||
|
||||
('install-headers=', None,
|
||||
"installation directory for C/C++ headers"),
|
||||
('install-scripts=', None,
|
||||
"installation directory for Python scripts"),
|
||||
('install-data=', None,
|
||||
"installation directory for data files"),
|
||||
(
|
||||
'install-headers=', None,
|
||||
'installation directory for C/C++ headers',
|
||||
),
|
||||
(
|
||||
'install-scripts=', None,
|
||||
'installation directory for Python scripts',
|
||||
),
|
||||
(
|
||||
'install-data=', None,
|
||||
'installation directory for data files',
|
||||
),
|
||||
|
||||
# Byte-compilation options -- see install_lib.py for details, as
|
||||
# these are duplicated from there (but only install_lib does
|
||||
# anything with them).
|
||||
('compile', 'c', "compile .py to .pyc [default]"),
|
||||
('compile', 'c', 'compile .py to .pyc [default]'),
|
||||
('no-compile', None, "don't compile .py files"),
|
||||
('optimize=', 'O',
|
||||
"also compile with optimization: -O1 for \"python -O\", "
|
||||
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
|
||||
(
|
||||
'optimize=', 'O',
|
||||
"also compile with optimization: -O1 for \"python -O\", "
|
||||
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]",
|
||||
),
|
||||
|
||||
# Miscellaneous control options
|
||||
('force', 'f',
|
||||
"force installation (overwrite any existing files)"),
|
||||
('skip-build', None,
|
||||
"skip rebuilding everything (for testing/debugging)"),
|
||||
(
|
||||
'force', 'f',
|
||||
'force installation (overwrite any existing files)',
|
||||
),
|
||||
(
|
||||
'skip-build', None,
|
||||
'skip rebuilding everything (for testing/debugging)',
|
||||
),
|
||||
|
||||
# Where to install documentation (eventually!)
|
||||
#('doc-format=', None, "format of documentation to generate"),
|
||||
|
|
@ -143,19 +175,22 @@ class install(Command):
|
|||
#('install-html=', None, "directory for HTML documentation"),
|
||||
#('install-info=', None, "directory for GNU info files"),
|
||||
|
||||
('record=', None,
|
||||
"filename in which to record list of installed files"),
|
||||
]
|
||||
(
|
||||
'record=', None,
|
||||
'filename in which to record list of installed files',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['compile', 'force', 'skip-build']
|
||||
|
||||
if HAS_USER_SITE:
|
||||
user_options.append(('user', None,
|
||||
"install in user site-package '%s'" % USER_SITE))
|
||||
user_options.append((
|
||||
'user', None,
|
||||
"install in user site-package '%s'" % USER_SITE,
|
||||
))
|
||||
boolean_options.append('user')
|
||||
|
||||
negative_opt = {'no-compile' : 'compile'}
|
||||
|
||||
negative_opt = {'no-compile': 'compile'}
|
||||
|
||||
def initialize_options(self):
|
||||
"""Initializes options."""
|
||||
|
|
@ -228,7 +263,6 @@ class install(Command):
|
|||
|
||||
self.record = None
|
||||
|
||||
|
||||
# -- Option finalizing methods -------------------------------------
|
||||
# (This is rather more involved than for most commands,
|
||||
# because this is where the policy for installing third-
|
||||
|
|
@ -252,24 +286,30 @@ class install(Command):
|
|||
# that's wrong on any platform.
|
||||
|
||||
if ((self.prefix or self.exec_prefix or self.home) and
|
||||
(self.install_base or self.install_platbase)):
|
||||
(self.install_base or self.install_platbase)):
|
||||
raise DistutilsOptionError(
|
||||
"must supply either prefix/exec-prefix/home or " +
|
||||
"install-base/install-platbase -- not both")
|
||||
'must supply either prefix/exec-prefix/home or ' +
|
||||
'install-base/install-platbase -- not both',
|
||||
)
|
||||
|
||||
if self.home and (self.prefix or self.exec_prefix):
|
||||
raise DistutilsOptionError(
|
||||
"must supply either home or prefix/exec-prefix -- not both")
|
||||
'must supply either home or prefix/exec-prefix -- not both',
|
||||
)
|
||||
|
||||
if self.user and (self.prefix or self.exec_prefix or self.home or
|
||||
self.install_base or self.install_platbase):
|
||||
raise DistutilsOptionError("can't combine user with prefix, "
|
||||
"exec_prefix/home, or install_(plat)base")
|
||||
if self.user and (
|
||||
self.prefix or self.exec_prefix or self.home or
|
||||
self.install_base or self.install_platbase
|
||||
):
|
||||
raise DistutilsOptionError(
|
||||
"can't combine user with prefix, "
|
||||
'exec_prefix/home, or install_(plat)base',
|
||||
)
|
||||
|
||||
# Next, stuff that's wrong (or dubious) only on certain platforms.
|
||||
if os.name != "posix":
|
||||
if os.name != 'posix':
|
||||
if self.exec_prefix:
|
||||
self.warn("exec-prefix option ignored on this platform")
|
||||
self.warn('exec-prefix option ignored on this platform')
|
||||
self.exec_prefix = None
|
||||
|
||||
# Now the interesting logic -- so interesting that we farm it out
|
||||
|
|
@ -280,14 +320,14 @@ class install(Command):
|
|||
# install_{purelib,platlib,lib,scripts,data,...}, and the
|
||||
# INSTALL_SCHEME dictionary above. Phew!
|
||||
|
||||
self.dump_dirs("pre-finalize_{unix,other}")
|
||||
self.dump_dirs('pre-finalize_{unix,other}')
|
||||
|
||||
if os.name == 'posix':
|
||||
self.finalize_unix()
|
||||
else:
|
||||
self.finalize_other()
|
||||
|
||||
self.dump_dirs("post-finalize_{unix,other}()")
|
||||
self.dump_dirs('post-finalize_{unix,other}()')
|
||||
|
||||
# Expand configuration variables, tilde, etc. in self.install_base
|
||||
# and self.install_platbase -- that way, we can use $base or
|
||||
|
|
@ -301,19 +341,20 @@ class install(Command):
|
|||
except AttributeError:
|
||||
# sys.abiflags may not be defined on all platforms.
|
||||
abiflags = ''
|
||||
self.config_vars = {'dist_name': self.distribution.get_name(),
|
||||
'dist_version': self.distribution.get_version(),
|
||||
'dist_fullname': self.distribution.get_fullname(),
|
||||
'py_version': py_version,
|
||||
'py_version_short': '%d.%d' % sys.version_info[:2],
|
||||
'py_version_nodot': '%d%d' % sys.version_info[:2],
|
||||
'sys_prefix': prefix,
|
||||
'prefix': prefix,
|
||||
'sys_exec_prefix': exec_prefix,
|
||||
'exec_prefix': exec_prefix,
|
||||
'abiflags': abiflags,
|
||||
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
|
||||
}
|
||||
self.config_vars = {
|
||||
'dist_name': self.distribution.get_name(),
|
||||
'dist_version': self.distribution.get_version(),
|
||||
'dist_fullname': self.distribution.get_fullname(),
|
||||
'py_version': py_version,
|
||||
'py_version_short': '%d.%d' % sys.version_info[:2],
|
||||
'py_version_nodot': '%d%d' % sys.version_info[:2],
|
||||
'sys_prefix': prefix,
|
||||
'prefix': prefix,
|
||||
'sys_exec_prefix': exec_prefix,
|
||||
'exec_prefix': exec_prefix,
|
||||
'abiflags': abiflags,
|
||||
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
|
||||
}
|
||||
|
||||
if HAS_USER_SITE:
|
||||
self.config_vars['userbase'] = self.install_userbase
|
||||
|
|
@ -321,7 +362,7 @@ class install(Command):
|
|||
|
||||
self.expand_basedirs()
|
||||
|
||||
self.dump_dirs("post-expand_basedirs()")
|
||||
self.dump_dirs('post-expand_basedirs()')
|
||||
|
||||
# Now define config vars for the base directories so we can expand
|
||||
# everything else.
|
||||
|
|
@ -330,14 +371,14 @@ class install(Command):
|
|||
|
||||
if DEBUG:
|
||||
from pprint import pprint
|
||||
print("config vars:")
|
||||
print('config vars:')
|
||||
pprint(self.config_vars)
|
||||
|
||||
# Expand "~" and configuration variables in the installation
|
||||
# directories.
|
||||
self.expand_dirs()
|
||||
|
||||
self.dump_dirs("post-expand_dirs()")
|
||||
self.dump_dirs('post-expand_dirs()')
|
||||
|
||||
# Create directories in the home dir:
|
||||
if self.user:
|
||||
|
|
@ -348,17 +389,18 @@ 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.has_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
|
||||
|
||||
|
||||
# Convert directories from Unix /-separated syntax to the local
|
||||
# convention.
|
||||
self.convert_paths('lib', 'purelib', 'platlib',
|
||||
'scripts', 'data', 'headers',
|
||||
'userbase', 'usersite')
|
||||
self.convert_paths(
|
||||
'lib', 'purelib', 'platlib',
|
||||
'scripts', 'data', 'headers',
|
||||
'userbase', 'usersite',
|
||||
)
|
||||
|
||||
# Deprecated
|
||||
# Well, we're not actually fully completely finalized yet: we still
|
||||
|
|
@ -366,21 +408,25 @@ class install(Command):
|
|||
# non-packagized module distributions (hello, Numerical Python!) to
|
||||
# get their own directories.
|
||||
self.handle_extra_path()
|
||||
self.install_libbase = self.install_lib # needed for .pth file
|
||||
self.install_libbase = self.install_lib # needed for .pth file
|
||||
self.install_lib = os.path.join(self.install_lib, self.extra_dirs)
|
||||
|
||||
# If a new root directory was supplied, make all the installation
|
||||
# dirs relative to it.
|
||||
if self.root is not None:
|
||||
self.change_roots('libbase', 'lib', 'purelib', 'platlib',
|
||||
'scripts', 'data', 'headers')
|
||||
self.change_roots(
|
||||
'libbase', 'lib', 'purelib', 'platlib',
|
||||
'scripts', 'data', 'headers',
|
||||
)
|
||||
|
||||
self.dump_dirs("after prepending root")
|
||||
self.dump_dirs('after prepending root')
|
||||
|
||||
# Find out the build directories, ie. where to install from.
|
||||
self.set_undefined_options('build',
|
||||
('build_base', 'build_base'),
|
||||
('build_lib', 'build_lib'))
|
||||
self.set_undefined_options(
|
||||
'build',
|
||||
('build_base', 'build_base'),
|
||||
('build_lib', 'build_lib'),
|
||||
)
|
||||
|
||||
# Punt on doc directories for now -- after all, we're punting on
|
||||
# documentation completely!
|
||||
|
|
@ -390,10 +436,10 @@ class install(Command):
|
|||
if not DEBUG:
|
||||
return
|
||||
from distutils.fancy_getopt import longopt_xlate
|
||||
log.debug(msg + ":")
|
||||
log.debug(msg + ':')
|
||||
for opt in self.user_options:
|
||||
opt_name = opt[0]
|
||||
if opt_name[-1] == "=":
|
||||
if opt_name[-1] == '=':
|
||||
opt_name = opt_name[0:-1]
|
||||
if opt_name in self.negative_opt:
|
||||
opt_name = self.negative_opt[opt_name]
|
||||
|
|
@ -402,36 +448,43 @@ class install(Command):
|
|||
else:
|
||||
opt_name = opt_name.translate(longopt_xlate)
|
||||
val = getattr(self, opt_name)
|
||||
log.debug(" %s: %s", opt_name, val)
|
||||
log.debug(' %s: %s', opt_name, val)
|
||||
|
||||
def finalize_unix(self):
|
||||
"""Finalizes options for posix platforms."""
|
||||
if self.install_base is not None or self.install_platbase is not None:
|
||||
if ((self.install_lib is None and
|
||||
self.install_purelib is None and
|
||||
self.install_platlib is None) or
|
||||
if (
|
||||
(
|
||||
self.install_lib is None and
|
||||
self.install_purelib is None and
|
||||
self.install_platlib is None
|
||||
) or
|
||||
self.install_headers is None or
|
||||
self.install_scripts is None or
|
||||
self.install_data is None):
|
||||
self.install_data is None
|
||||
):
|
||||
raise DistutilsOptionError(
|
||||
"install-base or install-platbase supplied, but "
|
||||
"installation scheme is incomplete")
|
||||
'install-base or install-platbase supplied, but '
|
||||
'installation scheme is incomplete',
|
||||
)
|
||||
return
|
||||
|
||||
if self.user:
|
||||
if self.install_userbase is None:
|
||||
raise DistutilsPlatformError(
|
||||
"User base directory is not specified")
|
||||
'User base directory is not specified',
|
||||
)
|
||||
self.install_base = self.install_platbase = self.install_userbase
|
||||
self.select_scheme("unix_user")
|
||||
self.select_scheme('unix_user')
|
||||
elif self.home is not None:
|
||||
self.install_base = self.install_platbase = self.home
|
||||
self.select_scheme("unix_home")
|
||||
self.select_scheme('unix_home')
|
||||
else:
|
||||
if self.prefix is None:
|
||||
if self.exec_prefix is not None:
|
||||
raise DistutilsOptionError(
|
||||
"must not supply exec-prefix without prefix")
|
||||
'must not supply exec-prefix without prefix',
|
||||
)
|
||||
|
||||
self.prefix = os.path.normpath(sys.prefix)
|
||||
self.exec_prefix = os.path.normpath(sys.exec_prefix)
|
||||
|
|
@ -442,19 +495,20 @@ class install(Command):
|
|||
|
||||
self.install_base = self.prefix
|
||||
self.install_platbase = self.exec_prefix
|
||||
self.select_scheme("unix_prefix")
|
||||
self.select_scheme('unix_prefix')
|
||||
|
||||
def finalize_other(self):
|
||||
"""Finalizes options for non-posix platforms"""
|
||||
if self.user:
|
||||
if self.install_userbase is None:
|
||||
raise DistutilsPlatformError(
|
||||
"User base directory is not specified")
|
||||
'User base directory is not specified',
|
||||
)
|
||||
self.install_base = self.install_platbase = self.install_userbase
|
||||
self.select_scheme(os.name + "_user")
|
||||
self.select_scheme(os.name + '_user')
|
||||
elif self.home is not None:
|
||||
self.install_base = self.install_platbase = self.home
|
||||
self.select_scheme("unix_home")
|
||||
self.select_scheme('unix_home')
|
||||
else:
|
||||
if self.prefix is None:
|
||||
self.prefix = os.path.normpath(sys.prefix)
|
||||
|
|
@ -464,14 +518,17 @@ class install(Command):
|
|||
self.select_scheme(os.name)
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"I don't know how to install stuff on '%s'" % os.name)
|
||||
"I don't know how to install stuff on '%s'" % os.name,
|
||||
)
|
||||
|
||||
def select_scheme(self, name):
|
||||
"""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 (
|
||||
hasattr(sys, 'pypy_version_info') and
|
||||
sys.version_info < (3, 8) and
|
||||
not name.endswith(('_user', '_home'))
|
||||
):
|
||||
if os.name == 'nt':
|
||||
name = 'pypy_nt'
|
||||
else:
|
||||
|
|
@ -498,14 +555,16 @@ class install(Command):
|
|||
|
||||
def expand_dirs(self):
|
||||
"""Calls `os.path.expanduser` on install dirs."""
|
||||
self._expand_attrs(['install_purelib', 'install_platlib',
|
||||
'install_lib', 'install_headers',
|
||||
'install_scripts', 'install_data',])
|
||||
self._expand_attrs([
|
||||
'install_purelib', 'install_platlib',
|
||||
'install_lib', 'install_headers',
|
||||
'install_scripts', 'install_data',
|
||||
])
|
||||
|
||||
def convert_paths(self, *names):
|
||||
"""Call `convert_path` over `names`."""
|
||||
for name in names:
|
||||
attr = "install_" + name
|
||||
attr = 'install_' + name
|
||||
setattr(self, attr, convert_path(getattr(self, attr)))
|
||||
|
||||
def handle_extra_path(self):
|
||||
|
|
@ -515,8 +574,8 @@ class install(Command):
|
|||
|
||||
if self.extra_path is not None:
|
||||
log.warn(
|
||||
"Distribution option extra_path is deprecated. "
|
||||
"See issue27919 for details."
|
||||
'Distribution option extra_path is deprecated. '
|
||||
'See issue27919 for details.',
|
||||
)
|
||||
if isinstance(self.extra_path, str):
|
||||
self.extra_path = self.extra_path.split(',')
|
||||
|
|
@ -527,8 +586,9 @@ class install(Command):
|
|||
path_file, extra_dirs = self.extra_path
|
||||
else:
|
||||
raise DistutilsOptionError(
|
||||
"'extra_path' option must be a list, tuple, or "
|
||||
"comma-separated string with 1 or 2 elements")
|
||||
"'extra_path' option must be a list, tuple, or "
|
||||
'comma-separated string with 1 or 2 elements',
|
||||
)
|
||||
|
||||
# convert to local form in case Unix notation used (as it
|
||||
# should be in setup scripts)
|
||||
|
|
@ -545,14 +605,14 @@ class install(Command):
|
|||
def change_roots(self, *names):
|
||||
"""Change the install directories pointed by name using root."""
|
||||
for name in names:
|
||||
attr = "install_" + name
|
||||
attr = 'install_' + name
|
||||
setattr(self, attr, change_root(self.root, getattr(self, attr)))
|
||||
|
||||
def create_home_path(self):
|
||||
"""Create directories under ~."""
|
||||
if not self.user:
|
||||
return
|
||||
home = convert_path(os.path.expanduser("~"))
|
||||
home = convert_path(os.path.expanduser('~'))
|
||||
for name, path in self.config_vars.items():
|
||||
if path.startswith(home) and not os.path.isdir(path):
|
||||
self.debug_print("os.makedirs('%s', 0o700)" % path)
|
||||
|
|
@ -571,8 +631,10 @@ class install(Command):
|
|||
# internally, and not to sys.path, so we don't check the platform
|
||||
# matches what we are running.
|
||||
if self.warn_dir and build_plat != get_platform():
|
||||
raise DistutilsPlatformError("Can't install when "
|
||||
"cross-compiling")
|
||||
raise DistutilsPlatformError(
|
||||
"Can't install when "
|
||||
'cross-compiling',
|
||||
)
|
||||
|
||||
# Run all sub-commands (at least those that need to be run)
|
||||
for cmd_name in self.get_sub_commands():
|
||||
|
|
@ -588,34 +650,45 @@ class install(Command):
|
|||
root_len = len(self.root)
|
||||
for counter in range(len(outputs)):
|
||||
outputs[counter] = outputs[counter][root_len:]
|
||||
self.execute(write_file,
|
||||
(self.record, outputs),
|
||||
"writing list of installed files to '%s'" %
|
||||
self.record)
|
||||
self.execute(
|
||||
write_file,
|
||||
(self.record, outputs),
|
||||
"writing list of installed files to '%s'" %
|
||||
self.record,
|
||||
)
|
||||
|
||||
sys_path = map(os.path.normpath, sys.path)
|
||||
sys_path = map(os.path.normcase, sys_path)
|
||||
install_lib = os.path.normcase(os.path.normpath(self.install_lib))
|
||||
if (self.warn_dir and
|
||||
if (
|
||||
self.warn_dir and
|
||||
not (self.path_file and self.install_path_file) and
|
||||
install_lib not in sys_path):
|
||||
log.debug(("modules installed to '%s', which is not in "
|
||||
"Python's module search path (sys.path) -- "
|
||||
"you'll have to change the search path yourself"),
|
||||
self.install_lib)
|
||||
install_lib not in sys_path
|
||||
):
|
||||
log.debug(
|
||||
(
|
||||
"modules installed to '%s', which is not in "
|
||||
"Python's module search path (sys.path) -- "
|
||||
"you'll have to change the search path yourself"
|
||||
),
|
||||
self.install_lib,
|
||||
)
|
||||
|
||||
def create_path_file(self):
|
||||
"""Creates the .pth file"""
|
||||
filename = os.path.join(self.install_libbase,
|
||||
self.path_file + ".pth")
|
||||
filename = os.path.join(
|
||||
self.install_libbase,
|
||||
self.path_file + '.pth',
|
||||
)
|
||||
if self.install_path_file:
|
||||
self.execute(write_file,
|
||||
(filename, [self.extra_dirs]),
|
||||
"creating %s" % filename)
|
||||
self.execute(
|
||||
write_file,
|
||||
(filename, [self.extra_dirs]),
|
||||
'creating %s' % filename,
|
||||
)
|
||||
else:
|
||||
self.warn("path file '%s' not created" % filename)
|
||||
|
||||
|
||||
# -- Reporting methods ---------------------------------------------
|
||||
|
||||
def get_outputs(self):
|
||||
|
|
@ -630,8 +703,12 @@ class install(Command):
|
|||
outputs.append(filename)
|
||||
|
||||
if self.path_file and self.install_path_file:
|
||||
outputs.append(os.path.join(self.install_libbase,
|
||||
self.path_file + ".pth"))
|
||||
outputs.append(
|
||||
os.path.join(
|
||||
self.install_libbase,
|
||||
self.path_file + '.pth',
|
||||
),
|
||||
)
|
||||
|
||||
return outputs
|
||||
|
||||
|
|
@ -650,8 +727,10 @@ class install(Command):
|
|||
def has_lib(self):
|
||||
"""Returns true if the current distribution has any Python
|
||||
modules to install."""
|
||||
return (self.distribution.has_pure_modules() or
|
||||
self.distribution.has_ext_modules())
|
||||
return (
|
||||
self.distribution.has_pure_modules() or
|
||||
self.distribution.has_ext_modules()
|
||||
)
|
||||
|
||||
def has_headers(self):
|
||||
"""Returns true if the current distribution has any headers to
|
||||
|
|
@ -670,9 +749,10 @@ class install(Command):
|
|||
|
||||
# 'sub_commands': a list of commands this command might have to run to
|
||||
# get its work done. See cmd.py for more info.
|
||||
sub_commands = [('install_lib', has_lib),
|
||||
('install_headers', has_headers),
|
||||
('install_scripts', has_scripts),
|
||||
('install_data', has_data),
|
||||
('install_egg_info', lambda self:True),
|
||||
]
|
||||
sub_commands = [
|
||||
('install_lib', has_lib),
|
||||
('install_headers', has_headers),
|
||||
('install_scripts', has_scripts),
|
||||
('install_data', has_data),
|
||||
('install_egg_info', lambda self: True),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,25 +2,32 @@
|
|||
|
||||
Implements the Distutils 'install_data' command, for installing
|
||||
platform-independent data files."""
|
||||
|
||||
# contributed by Bastian Kleineidam
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils.util import change_root, convert_path
|
||||
from distutils.util import change_root
|
||||
from distutils.util import convert_path
|
||||
|
||||
|
||||
class install_data(Command):
|
||||
|
||||
description = "install data files"
|
||||
description = 'install data files'
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd',
|
||||
"base directory for installing data files "
|
||||
"(default: installation base dir)"),
|
||||
('root=', None,
|
||||
"install everything relative to this alternate root directory"),
|
||||
('force', 'f', "force installation (overwrite existing files)"),
|
||||
]
|
||||
(
|
||||
'install-dir=', 'd',
|
||||
'base directory for installing data files '
|
||||
'(default: installation base dir)',
|
||||
),
|
||||
(
|
||||
'root=', None,
|
||||
'install everything relative to this alternate root directory',
|
||||
),
|
||||
('force', 'f', 'force installation (overwrite existing files)'),
|
||||
]
|
||||
|
||||
boolean_options = ['force']
|
||||
|
||||
|
|
@ -33,11 +40,12 @@ class install_data(Command):
|
|||
self.warn_dir = 1
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('install',
|
||||
('install_data', 'install_dir'),
|
||||
('root', 'root'),
|
||||
('force', 'force'),
|
||||
)
|
||||
self.set_undefined_options(
|
||||
'install',
|
||||
('install_data', 'install_dir'),
|
||||
('root', 'root'),
|
||||
('force', 'force'),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
self.mkpath(self.install_dir)
|
||||
|
|
@ -46,9 +54,11 @@ class install_data(Command):
|
|||
# it's a simple file, so copy it
|
||||
f = convert_path(f)
|
||||
if self.warn_dir:
|
||||
self.warn("setup script did not provide a directory for "
|
||||
"'%s' -- installing right in '%s'" %
|
||||
(f, self.install_dir))
|
||||
self.warn(
|
||||
'setup script did not provide a directory for '
|
||||
"'%s' -- installing right in '%s'" %
|
||||
(f, self.install_dir),
|
||||
)
|
||||
(out, _) = self.copy_file(f, self.install_dir)
|
||||
self.outfiles.append(out)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -2,29 +2,34 @@
|
|||
|
||||
Implements the Distutils 'install_egg_info' command, for installing
|
||||
a package's PKG-INFO metadata."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from distutils import dir_util
|
||||
from distutils import log
|
||||
from distutils.cmd import Command
|
||||
from distutils import log, dir_util
|
||||
import os, sys, re
|
||||
|
||||
|
||||
class install_egg_info(Command):
|
||||
"""Install an .egg-info file for the package"""
|
||||
|
||||
description = "Install package's PKG-INFO metadata as an .egg-info file"
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install to"),
|
||||
('install-dir=', 'd', 'directory to install to'),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.install_dir = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('install_lib',('install_dir','install_dir'))
|
||||
basename = "%s-%s-py%d.%d.egg-info" % (
|
||||
self.set_undefined_options('install_lib', ('install_dir', 'install_dir'))
|
||||
basename = '%s-%s-py%d.%d.egg-info' % (
|
||||
to_filename(safe_name(self.distribution.get_name())),
|
||||
to_filename(safe_version(self.distribution.get_version())),
|
||||
*sys.version_info[:2]
|
||||
*sys.version_info[:2],
|
||||
)
|
||||
self.target = os.path.join(self.install_dir, basename)
|
||||
self.outputs = [self.target]
|
||||
|
|
@ -34,11 +39,13 @@ class install_egg_info(Command):
|
|||
if os.path.isdir(target) and not os.path.islink(target):
|
||||
dir_util.remove_tree(target, dry_run=self.dry_run)
|
||||
elif os.path.exists(target):
|
||||
self.execute(os.unlink,(self.target,),"Removing "+target)
|
||||
self.execute(os.unlink, (self.target,), 'Removing ' + target)
|
||||
elif not os.path.isdir(self.install_dir):
|
||||
self.execute(os.makedirs, (self.install_dir,),
|
||||
"Creating "+self.install_dir)
|
||||
log.info("Writing %s", target)
|
||||
self.execute(
|
||||
os.makedirs, (self.install_dir,),
|
||||
'Creating ' + self.install_dir,
|
||||
)
|
||||
log.info('Writing %s', target)
|
||||
if not self.dry_run:
|
||||
with open(target, 'w', encoding='UTF-8') as f:
|
||||
self.distribution.metadata.write_pkg_file(f)
|
||||
|
|
@ -65,7 +72,7 @@ def safe_version(version):
|
|||
Spaces become dots, and all other non-alphanumeric characters become
|
||||
dashes, with runs of multiple dashes condensed to a single dash.
|
||||
"""
|
||||
version = version.replace(' ','.')
|
||||
version = version.replace(' ', '.')
|
||||
return re.sub('[^A-Za-z0-9.]+', '-', version)
|
||||
|
||||
|
||||
|
|
@ -74,4 +81,4 @@ def to_filename(name):
|
|||
|
||||
Any '-' characters are currently replaced with '_'.
|
||||
"""
|
||||
return name.replace('-','_')
|
||||
return name.replace('-', '_')
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
Implements the Distutils 'install_headers' command, to install C/C++ header
|
||||
files to the Python include directory."""
|
||||
from __future__ import annotations
|
||||
|
||||
from distutils.core import Command
|
||||
|
||||
|
|
@ -9,13 +10,18 @@ from distutils.core import Command
|
|||
# XXX force is never used
|
||||
class install_headers(Command):
|
||||
|
||||
description = "install C/C++ header files"
|
||||
description = 'install C/C++ header files'
|
||||
|
||||
user_options = [('install-dir=', 'd',
|
||||
"directory to install header files to"),
|
||||
('force', 'f',
|
||||
"force installation (overwrite existing files)"),
|
||||
]
|
||||
user_options = [
|
||||
(
|
||||
'install-dir=', 'd',
|
||||
'directory to install header files to',
|
||||
),
|
||||
(
|
||||
'force', 'f',
|
||||
'force installation (overwrite existing files)',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['force']
|
||||
|
||||
|
|
@ -25,10 +31,11 @@ class install_headers(Command):
|
|||
self.outfiles = []
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('install',
|
||||
('install_headers', 'install_dir'),
|
||||
('force', 'force'))
|
||||
|
||||
self.set_undefined_options(
|
||||
'install',
|
||||
('install_headers', 'install_dir'),
|
||||
('force', 'force'),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
headers = self.distribution.headers
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
Implements the Distutils 'install_lib' command
|
||||
(install all Python modules)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import importlib.util
|
||||
import os
|
||||
import sys
|
||||
|
||||
from distutils.core import Command
|
||||
|
|
@ -12,11 +13,12 @@ from distutils.errors import DistutilsOptionError
|
|||
|
||||
|
||||
# Extension for Python source files.
|
||||
PYTHON_SOURCE_EXTENSION = ".py"
|
||||
PYTHON_SOURCE_EXTENSION = '.py'
|
||||
|
||||
|
||||
class install_lib(Command):
|
||||
|
||||
description = "install all Python modules (extensions and pure Python)"
|
||||
description = 'install all Python modules (extensions and pure Python)'
|
||||
|
||||
# The byte-compilation options are a tad confusing. Here are the
|
||||
# possible scenarios:
|
||||
|
|
@ -34,19 +36,21 @@ class install_lib(Command):
|
|||
# optimization to use.
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install to"),
|
||||
('build-dir=','b', "build directory (where to install from)"),
|
||||
('force', 'f', "force installation (overwrite existing files)"),
|
||||
('compile', 'c', "compile .py to .pyc [default]"),
|
||||
('install-dir=', 'd', 'directory to install to'),
|
||||
('build-dir=', 'b', 'build directory (where to install from)'),
|
||||
('force', 'f', 'force installation (overwrite existing files)'),
|
||||
('compile', 'c', 'compile .py to .pyc [default]'),
|
||||
('no-compile', None, "don't compile .py files"),
|
||||
('optimize=', 'O',
|
||||
"also compile with optimization: -O1 for \"python -O\", "
|
||||
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
|
||||
('skip-build', None, "skip the build steps"),
|
||||
]
|
||||
(
|
||||
'optimize=', 'O',
|
||||
"also compile with optimization: -O1 for \"python -O\", "
|
||||
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]",
|
||||
),
|
||||
('skip-build', None, 'skip the build steps'),
|
||||
]
|
||||
|
||||
boolean_options = ['force', 'compile', 'skip-build']
|
||||
negative_opt = {'no-compile' : 'compile'}
|
||||
negative_opt = {'no-compile': 'compile'}
|
||||
|
||||
def initialize_options(self):
|
||||
# let the 'install' command dictate our installation directory
|
||||
|
|
@ -61,14 +65,15 @@ class install_lib(Command):
|
|||
# Get all the information we need to install pure Python modules
|
||||
# from the umbrella 'install' command -- build (source) directory,
|
||||
# install (target) directory, and whether to compile .py files.
|
||||
self.set_undefined_options('install',
|
||||
('build_lib', 'build_dir'),
|
||||
('install_lib', 'install_dir'),
|
||||
('force', 'force'),
|
||||
('compile', 'compile'),
|
||||
('optimize', 'optimize'),
|
||||
('skip_build', 'skip_build'),
|
||||
)
|
||||
self.set_undefined_options(
|
||||
'install',
|
||||
('build_lib', 'build_dir'),
|
||||
('install_lib', 'install_dir'),
|
||||
('force', 'force'),
|
||||
('compile', 'compile'),
|
||||
('optimize', 'optimize'),
|
||||
('skip_build', 'skip_build'),
|
||||
)
|
||||
|
||||
if self.compile is None:
|
||||
self.compile = True
|
||||
|
|
@ -81,7 +86,7 @@ class install_lib(Command):
|
|||
if self.optimize not in (0, 1, 2):
|
||||
raise AssertionError
|
||||
except (ValueError, AssertionError):
|
||||
raise DistutilsOptionError("optimize must be 0, 1, or 2")
|
||||
raise DistutilsOptionError('optimize must be 0, 1, or 2')
|
||||
|
||||
def run(self):
|
||||
# Make sure we have built everything we need first
|
||||
|
|
@ -110,8 +115,10 @@ class install_lib(Command):
|
|||
if os.path.isdir(self.build_dir):
|
||||
outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
||||
else:
|
||||
self.warn("'%s' does not exist -- no Python modules to install" %
|
||||
self.build_dir)
|
||||
self.warn(
|
||||
"'%s' does not exist -- no Python modules to install" %
|
||||
self.build_dir,
|
||||
)
|
||||
return
|
||||
return outfiles
|
||||
|
||||
|
|
@ -129,14 +136,17 @@ class install_lib(Command):
|
|||
install_root = self.get_finalized_command('install').root
|
||||
|
||||
if self.compile:
|
||||
byte_compile(files, optimize=0,
|
||||
force=self.force, prefix=install_root,
|
||||
dry_run=self.dry_run)
|
||||
byte_compile(
|
||||
files, optimize=0,
|
||||
force=self.force, prefix=install_root,
|
||||
dry_run=self.dry_run,
|
||||
)
|
||||
if self.optimize > 0:
|
||||
byte_compile(files, optimize=self.optimize,
|
||||
force=self.force, prefix=install_root,
|
||||
verbose=self.verbose, dry_run=self.dry_run)
|
||||
|
||||
byte_compile(
|
||||
files, optimize=self.optimize,
|
||||
force=self.force, prefix=install_root,
|
||||
verbose=self.verbose, dry_run=self.dry_run,
|
||||
)
|
||||
|
||||
# -- Utility methods -----------------------------------------------
|
||||
|
||||
|
|
@ -165,15 +175,20 @@ class install_lib(Command):
|
|||
if ext != PYTHON_SOURCE_EXTENSION:
|
||||
continue
|
||||
if self.compile:
|
||||
bytecode_files.append(importlib.util.cache_from_source(
|
||||
py_file, optimization=''))
|
||||
bytecode_files.append(
|
||||
importlib.util.cache_from_source(
|
||||
py_file, optimization='',
|
||||
),
|
||||
)
|
||||
if self.optimize > 0:
|
||||
bytecode_files.append(importlib.util.cache_from_source(
|
||||
py_file, optimization=self.optimize))
|
||||
bytecode_files.append(
|
||||
importlib.util.cache_from_source(
|
||||
py_file, optimization=self.optimize,
|
||||
),
|
||||
)
|
||||
|
||||
return bytecode_files
|
||||
|
||||
|
||||
# -- External interface --------------------------------------------
|
||||
# (called by outsiders)
|
||||
|
||||
|
|
@ -183,18 +198,22 @@ class install_lib(Command):
|
|||
modules have actually been built yet.
|
||||
"""
|
||||
pure_outputs = \
|
||||
self._mutate_outputs(self.distribution.has_pure_modules(),
|
||||
'build_py', 'build_lib',
|
||||
self.install_dir)
|
||||
self._mutate_outputs(
|
||||
self.distribution.has_pure_modules(),
|
||||
'build_py', 'build_lib',
|
||||
self.install_dir,
|
||||
)
|
||||
if self.compile:
|
||||
bytecode_outputs = self._bytecode_filenames(pure_outputs)
|
||||
else:
|
||||
bytecode_outputs = []
|
||||
|
||||
ext_outputs = \
|
||||
self._mutate_outputs(self.distribution.has_ext_modules(),
|
||||
'build_ext', 'build_lib',
|
||||
self.install_dir)
|
||||
self._mutate_outputs(
|
||||
self.distribution.has_ext_modules(),
|
||||
'build_ext', 'build_lib',
|
||||
self.install_dir,
|
||||
)
|
||||
|
||||
return pure_outputs + bytecode_outputs + ext_outputs
|
||||
|
||||
|
|
|
|||
|
|
@ -2,24 +2,25 @@
|
|||
|
||||
Implements the Distutils 'install_scripts' command, for installing
|
||||
Python scripts."""
|
||||
|
||||
# contributed by Bastian Kleineidam
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from distutils.core import Command
|
||||
from distutils import log
|
||||
from stat import ST_MODE
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
|
||||
|
||||
class install_scripts(Command):
|
||||
|
||||
description = "install scripts (Python or otherwise)"
|
||||
description = 'install scripts (Python or otherwise)'
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install scripts to"),
|
||||
('build-dir=','b', "build directory (where to install from)"),
|
||||
('force', 'f', "force installation (overwrite existing files)"),
|
||||
('skip-build', None, "skip the build steps"),
|
||||
('install-dir=', 'd', 'directory to install scripts to'),
|
||||
('build-dir=', 'b', 'build directory (where to install from)'),
|
||||
('force', 'f', 'force installation (overwrite existing files)'),
|
||||
('skip-build', None, 'skip the build steps'),
|
||||
]
|
||||
|
||||
boolean_options = ['force', 'skip-build']
|
||||
|
|
@ -32,11 +33,12 @@ class install_scripts(Command):
|
|||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('build', ('build_scripts', 'build_dir'))
|
||||
self.set_undefined_options('install',
|
||||
('install_scripts', 'install_dir'),
|
||||
('force', 'force'),
|
||||
('skip_build', 'skip_build'),
|
||||
)
|
||||
self.set_undefined_options(
|
||||
'install',
|
||||
('install_scripts', 'install_dir'),
|
||||
('force', 'force'),
|
||||
('skip_build', 'skip_build'),
|
||||
)
|
||||
|
||||
def run(self):
|
||||
if not self.skip_build:
|
||||
|
|
@ -47,10 +49,10 @@ class install_scripts(Command):
|
|||
# all the scripts we just installed.
|
||||
for file in self.get_outputs():
|
||||
if self.dry_run:
|
||||
log.info("changing mode of %s", file)
|
||||
log.info('changing mode of %s', file)
|
||||
else:
|
||||
mode = ((os.stat(file)[ST_MODE]) | 0o555) & 0o7777
|
||||
log.info("changing mode of %s to %o", file, mode)
|
||||
log.info('changing mode of %s to %o', file, mode)
|
||||
os.chmod(file, mode)
|
||||
|
||||
def get_inputs(self):
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
|
|
@ -23,8 +25,8 @@ def compose(f1, f2):
|
|||
|
||||
pythonlib = (
|
||||
compose(list, _pythonlib_compat)
|
||||
if sys.version_info < (3, 8)
|
||||
and sys.platform != 'darwin'
|
||||
and sys.platform[:3] != 'aix'
|
||||
if sys.version_info < (3, 8) and
|
||||
sys.platform != 'darwin' and
|
||||
sys.platform[:3] != 'aix'
|
||||
else list
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,29 +2,36 @@
|
|||
|
||||
Implements the Distutils 'register' command (register with the repository).
|
||||
"""
|
||||
|
||||
# created 2002/10/21, Richard Jones
|
||||
from __future__ import annotations
|
||||
|
||||
import getpass
|
||||
import io
|
||||
import urllib.parse, urllib.request
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from warnings import warn
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import PyPIRCCommand
|
||||
from distutils.errors import *
|
||||
from distutils import log
|
||||
|
||||
|
||||
class register(PyPIRCCommand):
|
||||
|
||||
description = ("register the distribution with the Python package index")
|
||||
description = ('register the distribution with the Python package index')
|
||||
user_options = PyPIRCCommand.user_options + [
|
||||
('list-classifiers', None,
|
||||
'list the valid Trove classifiers'),
|
||||
('strict', None ,
|
||||
'Will stop the registering if the meta-data are not fully compliant')
|
||||
]
|
||||
(
|
||||
'list-classifiers', None,
|
||||
'list the valid Trove classifiers',
|
||||
),
|
||||
(
|
||||
'strict', None,
|
||||
'Will stop the registering if the meta-data are not fully compliant',
|
||||
),
|
||||
]
|
||||
boolean_options = PyPIRCCommand.boolean_options + [
|
||||
'verify', 'list-classifiers', 'strict']
|
||||
'verify', 'list-classifiers', 'strict',
|
||||
]
|
||||
|
||||
sub_commands = [('check', lambda self: True)]
|
||||
|
||||
|
|
@ -36,8 +43,10 @@ class register(PyPIRCCommand):
|
|||
def finalize_options(self):
|
||||
PyPIRCCommand.finalize_options(self)
|
||||
# setting options for the `check` subcommand
|
||||
check_options = {'strict': ('register', self.strict),
|
||||
'restructuredtext': ('register', 1)}
|
||||
check_options = {
|
||||
'strict': ('register', self.strict),
|
||||
'restructuredtext': ('register', 1),
|
||||
}
|
||||
self.distribution.command_options['check'] = check_options
|
||||
|
||||
def run(self):
|
||||
|
|
@ -57,8 +66,10 @@ class register(PyPIRCCommand):
|
|||
|
||||
def check_metadata(self):
|
||||
"""Deprecated API."""
|
||||
warn("distutils.command.register.check_metadata is deprecated, \
|
||||
use the check command instead", PendingDeprecationWarning)
|
||||
warn(
|
||||
'distutils.command.register.check_metadata is deprecated, \
|
||||
use the check command instead', PendingDeprecationWarning,
|
||||
)
|
||||
check = self.distribution.get_command_obj('check')
|
||||
check.ensure_finalized()
|
||||
check.strict = self.strict
|
||||
|
|
@ -85,7 +96,7 @@ class register(PyPIRCCommand):
|
|||
def classifiers(self):
|
||||
''' Fetch the list of classifiers from the server.
|
||||
'''
|
||||
url = self.repository+'?:action=list_classifiers'
|
||||
url = self.repository + '?:action=list_classifiers'
|
||||
response = urllib.request.urlopen(url)
|
||||
log.info(self._read_pypi_response(response))
|
||||
|
||||
|
|
@ -137,13 +148,15 @@ class register(PyPIRCCommand):
|
|||
# get the user's login info
|
||||
choices = '1 2 3 4'.split()
|
||||
while choice not in choices:
|
||||
self.announce('''\
|
||||
self.announce(
|
||||
'''\
|
||||
We need to know who you are, so please choose either:
|
||||
1. use your existing login,
|
||||
2. register as a new user,
|
||||
3. have the server generate a new password for you (and email it to you), or
|
||||
4. quit
|
||||
Your selection [default 1]: ''', log.INFO)
|
||||
Your selection [default 1]: ''', log.INFO,
|
||||
)
|
||||
choice = input()
|
||||
if not choice:
|
||||
choice = '1'
|
||||
|
|
@ -162,10 +175,14 @@ Your selection [default 1]: ''', log.INFO)
|
|||
host = urllib.parse.urlparse(self.repository)[1]
|
||||
auth.add_password(self.realm, host, username, password)
|
||||
# send the info to the server and report the result
|
||||
code, result = self.post_to_server(self.build_post_data('submit'),
|
||||
auth)
|
||||
self.announce('Server response (%s): %s' % (code, result),
|
||||
log.INFO)
|
||||
code, result = self.post_to_server(
|
||||
self.build_post_data('submit'),
|
||||
auth,
|
||||
)
|
||||
self.announce(
|
||||
'Server response ({}): {}'.format(code, result),
|
||||
log.INFO,
|
||||
)
|
||||
|
||||
# possibly save the login
|
||||
if code == 200:
|
||||
|
|
@ -174,10 +191,16 @@ Your selection [default 1]: ''', log.INFO)
|
|||
# so the upload command can reuse it
|
||||
self.distribution.password = password
|
||||
else:
|
||||
self.announce(('I can store your PyPI login so future '
|
||||
'submissions will be faster.'), log.INFO)
|
||||
self.announce('(the login will be stored in %s)' % \
|
||||
self._get_rc_file(), log.INFO)
|
||||
self.announce(
|
||||
(
|
||||
'I can store your PyPI login so future '
|
||||
'submissions will be faster.'
|
||||
), log.INFO,
|
||||
)
|
||||
self.announce(
|
||||
'(the login will be stored in %s)' %
|
||||
self._get_rc_file(), log.INFO,
|
||||
)
|
||||
choice = 'X'
|
||||
while choice.lower() not in 'yn':
|
||||
choice = input('Save your login (y/N)?')
|
||||
|
|
@ -208,8 +231,10 @@ Your selection [default 1]: ''', log.INFO)
|
|||
log.info('Server response (%s): %s', code, result)
|
||||
else:
|
||||
log.info('You will receive an email shortly.')
|
||||
log.info(('Follow the instructions in it to '
|
||||
'complete registration.'))
|
||||
log.info(
|
||||
'Follow the instructions in it to '
|
||||
'complete registration.'
|
||||
)
|
||||
elif choice == '3':
|
||||
data = {':action': 'password_reset'}
|
||||
data['email'] = ''
|
||||
|
|
@ -224,7 +249,7 @@ Your selection [default 1]: ''', log.INFO)
|
|||
meta = self.distribution.metadata
|
||||
data = {
|
||||
':action': action,
|
||||
'metadata_version' : '1.0',
|
||||
'metadata_version': '1.0',
|
||||
'name': meta.get_name(),
|
||||
'version': meta.get_version(),
|
||||
'summary': meta.get_description(),
|
||||
|
|
@ -250,9 +275,13 @@ Your selection [default 1]: ''', log.INFO)
|
|||
''' Post a query to the server, and return a string response.
|
||||
'''
|
||||
if 'name' in data:
|
||||
self.announce('Registering %s to %s' % (data['name'],
|
||||
self.repository),
|
||||
log.INFO)
|
||||
self.announce(
|
||||
'Registering {} to {}'.format(
|
||||
data['name'],
|
||||
self.repository,
|
||||
),
|
||||
log.INFO,
|
||||
)
|
||||
# Build up the MIME payload for the urllib2 POST data
|
||||
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
sep_boundary = '\n--' + boundary
|
||||
|
|
@ -260,30 +289,30 @@ Your selection [default 1]: ''', log.INFO)
|
|||
body = io.StringIO()
|
||||
for key, value in data.items():
|
||||
# handle multiple entries for the same name
|
||||
if type(value) not in (type([]), type( () )):
|
||||
if type(value) not in (type([]), type(())):
|
||||
value = [value]
|
||||
for value in value:
|
||||
value = str(value)
|
||||
body.write(sep_boundary)
|
||||
body.write('\nContent-Disposition: form-data; name="%s"'%key)
|
||||
body.write("\n\n")
|
||||
body.write('\nContent-Disposition: form-data; name="%s"' % key)
|
||||
body.write('\n\n')
|
||||
body.write(value)
|
||||
if value and value[-1] == '\r':
|
||||
body.write('\n') # write an extra newline (lurve Macs)
|
||||
body.write(end_boundary)
|
||||
body.write("\n")
|
||||
body = body.getvalue().encode("utf-8")
|
||||
body.write('\n')
|
||||
body = body.getvalue().encode('utf-8')
|
||||
|
||||
# build the Request
|
||||
headers = {
|
||||
'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary,
|
||||
'Content-length': str(len(body))
|
||||
'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8' % boundary,
|
||||
'Content-length': str(len(body)),
|
||||
}
|
||||
req = urllib.request.Request(self.repository, body, headers)
|
||||
|
||||
# handle HTTP and include the Basic Auth handler
|
||||
opener = urllib.request.build_opener(
|
||||
urllib.request.HTTPBasicAuthHandler(password_mgr=auth)
|
||||
urllib.request.HTTPBasicAuthHandler(password_mgr=auth),
|
||||
)
|
||||
data = ''
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
"""distutils.command.sdist
|
||||
|
||||
Implements the Distutils 'sdist' command (create a source distribution)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from glob import glob
|
||||
from warnings import warn
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils import archive_util
|
||||
from distutils import dir_util
|
||||
from distutils import file_util
|
||||
from distutils import archive_util
|
||||
from distutils.text_file import TextFile
|
||||
from distutils.filelist import FileList
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.errors import DistutilsTemplateError
|
||||
from distutils.filelist import FileList
|
||||
from distutils.text_file import TextFile
|
||||
from distutils.util import convert_path
|
||||
from distutils.errors import DistutilsTemplateError, DistutilsOptionError
|
||||
|
||||
|
||||
def show_formats():
|
||||
|
|
@ -26,16 +28,19 @@ def show_formats():
|
|||
from distutils.archive_util import ARCHIVE_FORMATS
|
||||
formats = []
|
||||
for format in ARCHIVE_FORMATS.keys():
|
||||
formats.append(("formats=" + format, None,
|
||||
ARCHIVE_FORMATS[format][2]))
|
||||
formats.append((
|
||||
'formats=' + format, None,
|
||||
ARCHIVE_FORMATS[format][2],
|
||||
))
|
||||
formats.sort()
|
||||
FancyGetopt(formats).print_help(
|
||||
"List of available source distribution formats:")
|
||||
'List of available source distribution formats:',
|
||||
)
|
||||
|
||||
|
||||
class sdist(Command):
|
||||
|
||||
description = "create a source distribution (tarball, zip file, etc.)"
|
||||
description = 'create a source distribution (tarball, zip file, etc.)'
|
||||
|
||||
def checking_metadata(self):
|
||||
"""Callable used for the check sub-command.
|
||||
|
|
@ -44,55 +49,88 @@ class sdist(Command):
|
|||
return self.metadata_check
|
||||
|
||||
user_options = [
|
||||
('template=', 't',
|
||||
"name of manifest template file [default: MANIFEST.in]"),
|
||||
('manifest=', 'm',
|
||||
"name of manifest file [default: MANIFEST]"),
|
||||
('use-defaults', None,
|
||||
"include the default file set in the manifest "
|
||||
"[default; disable with --no-defaults]"),
|
||||
('no-defaults', None,
|
||||
"don't include the default file set"),
|
||||
('prune', None,
|
||||
"specifically exclude files/directories that should not be "
|
||||
"distributed (build tree, RCS/CVS dirs, etc.) "
|
||||
"[default; disable with --no-prune]"),
|
||||
('no-prune', None,
|
||||
"don't automatically exclude anything"),
|
||||
('manifest-only', 'o',
|
||||
"just regenerate the manifest and then stop "
|
||||
"(implies --force-manifest)"),
|
||||
('force-manifest', 'f',
|
||||
"forcibly regenerate the manifest and carry on as usual. "
|
||||
"Deprecated: now the manifest is always regenerated."),
|
||||
('formats=', None,
|
||||
"formats for source distribution (comma-separated list)"),
|
||||
('keep-temp', 'k',
|
||||
"keep the distribution tree around after creating " +
|
||||
"archive file(s)"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put the source distribution archive(s) in "
|
||||
"[default: dist]"),
|
||||
('metadata-check', None,
|
||||
"Ensure that all required elements of meta-data "
|
||||
"are supplied. Warn if any missing. [default]"),
|
||||
('owner=', 'u',
|
||||
"Owner name used when creating a tar file [default: current user]"),
|
||||
('group=', 'g',
|
||||
"Group name used when creating a tar file [default: current group]"),
|
||||
]
|
||||
(
|
||||
'template=', 't',
|
||||
'name of manifest template file [default: MANIFEST.in]',
|
||||
),
|
||||
(
|
||||
'manifest=', 'm',
|
||||
'name of manifest file [default: MANIFEST]',
|
||||
),
|
||||
(
|
||||
'use-defaults', None,
|
||||
'include the default file set in the manifest '
|
||||
'[default; disable with --no-defaults]',
|
||||
),
|
||||
(
|
||||
'no-defaults', None,
|
||||
"don't include the default file set",
|
||||
),
|
||||
(
|
||||
'prune', None,
|
||||
'specifically exclude files/directories that should not be '
|
||||
'distributed (build tree, RCS/CVS dirs, etc.) '
|
||||
'[default; disable with --no-prune]',
|
||||
),
|
||||
(
|
||||
'no-prune', None,
|
||||
"don't automatically exclude anything",
|
||||
),
|
||||
(
|
||||
'manifest-only', 'o',
|
||||
'just regenerate the manifest and then stop '
|
||||
'(implies --force-manifest)',
|
||||
),
|
||||
(
|
||||
'force-manifest', 'f',
|
||||
'forcibly regenerate the manifest and carry on as usual. '
|
||||
'Deprecated: now the manifest is always regenerated.',
|
||||
),
|
||||
(
|
||||
'formats=', None,
|
||||
'formats for source distribution (comma-separated list)',
|
||||
),
|
||||
(
|
||||
'keep-temp', 'k',
|
||||
'keep the distribution tree around after creating ' +
|
||||
'archive file(s)',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put the source distribution archive(s) in '
|
||||
'[default: dist]',
|
||||
),
|
||||
(
|
||||
'metadata-check', None,
|
||||
'Ensure that all required elements of meta-data '
|
||||
'are supplied. Warn if any missing. [default]',
|
||||
),
|
||||
(
|
||||
'owner=', 'u',
|
||||
'Owner name used when creating a tar file [default: current user]',
|
||||
),
|
||||
(
|
||||
'group=', 'g',
|
||||
'Group name used when creating a tar file [default: current group]',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['use-defaults', 'prune',
|
||||
'manifest-only', 'force-manifest',
|
||||
'keep-temp', 'metadata-check']
|
||||
boolean_options = [
|
||||
'use-defaults', 'prune',
|
||||
'manifest-only', 'force-manifest',
|
||||
'keep-temp', 'metadata-check',
|
||||
]
|
||||
|
||||
help_options = [
|
||||
('help-formats', None,
|
||||
"list available distribution formats", show_formats),
|
||||
]
|
||||
(
|
||||
'help-formats', None,
|
||||
'list available distribution formats', show_formats,
|
||||
),
|
||||
]
|
||||
|
||||
negative_opt = {'no-defaults': 'use-defaults',
|
||||
'no-prune': 'prune' }
|
||||
negative_opt = {
|
||||
'no-defaults': 'use-defaults',
|
||||
'no-prune': 'prune', }
|
||||
|
||||
sub_commands = [('check', checking_metadata)]
|
||||
|
||||
|
|
@ -123,19 +161,20 @@ class sdist(Command):
|
|||
|
||||
def finalize_options(self):
|
||||
if self.manifest is None:
|
||||
self.manifest = "MANIFEST"
|
||||
self.manifest = 'MANIFEST'
|
||||
if self.template is None:
|
||||
self.template = "MANIFEST.in"
|
||||
self.template = 'MANIFEST.in'
|
||||
|
||||
self.ensure_string_list('formats')
|
||||
|
||||
bad_format = archive_util.check_archive_formats(self.formats)
|
||||
if bad_format:
|
||||
raise DistutilsOptionError(
|
||||
"unknown archive format '%s'" % bad_format)
|
||||
"unknown archive format '%s'" % bad_format,
|
||||
)
|
||||
|
||||
if self.dist_dir is None:
|
||||
self.dist_dir = "dist"
|
||||
self.dist_dir = 'dist'
|
||||
|
||||
def run(self):
|
||||
# 'filelist' contains the list of files that will make up the
|
||||
|
|
@ -161,8 +200,10 @@ class sdist(Command):
|
|||
|
||||
def check_metadata(self):
|
||||
"""Deprecated API."""
|
||||
warn("distutils.command.sdist.check_metadata is deprecated, \
|
||||
use the check command instead", PendingDeprecationWarning)
|
||||
warn(
|
||||
'distutils.command.sdist.check_metadata is deprecated, \
|
||||
use the check command instead', PendingDeprecationWarning,
|
||||
)
|
||||
check = self.distribution.get_command_obj('check')
|
||||
check.ensure_finalized()
|
||||
check.run()
|
||||
|
|
@ -189,9 +230,13 @@ class sdist(Command):
|
|||
return
|
||||
|
||||
if not template_exists:
|
||||
self.warn(("manifest template '%s' does not exist " +
|
||||
"(using default file list)") %
|
||||
self.template)
|
||||
self.warn(
|
||||
(
|
||||
"manifest template '%s' does not exist " +
|
||||
'(using default file list)'
|
||||
) %
|
||||
self.template,
|
||||
)
|
||||
self.filelist.findall()
|
||||
|
||||
if self.use_defaults:
|
||||
|
|
@ -259,8 +304,10 @@ class sdist(Command):
|
|||
break
|
||||
|
||||
if not got_it:
|
||||
self.warn("standard file not found: should have one of " +
|
||||
', '.join(alts))
|
||||
self.warn(
|
||||
'standard file not found: should have one of ' +
|
||||
', '.join(alts),
|
||||
)
|
||||
else:
|
||||
if self._cs_path_exists(fn):
|
||||
self.filelist.append(fn)
|
||||
|
|
@ -328,9 +375,11 @@ class sdist(Command):
|
|||
'self.filelist', which updates itself accordingly.
|
||||
"""
|
||||
log.info("reading manifest template '%s'", self.template)
|
||||
template = TextFile(self.template, strip_comments=1, skip_blanks=1,
|
||||
join_lines=1, lstrip_ws=1, rstrip_ws=1,
|
||||
collapse_join=1)
|
||||
template = TextFile(
|
||||
self.template, strip_comments=1, skip_blanks=1,
|
||||
join_lines=1, lstrip_ws=1, rstrip_ws=1,
|
||||
collapse_join=1,
|
||||
)
|
||||
|
||||
try:
|
||||
while True:
|
||||
|
|
@ -344,9 +393,13 @@ class sdist(Command):
|
|||
# malformed lines, or a ValueError from the lower-level
|
||||
# convert_path function
|
||||
except (DistutilsTemplateError, ValueError) as msg:
|
||||
self.warn("%s, line %d: %s" % (template.filename,
|
||||
template.current_line,
|
||||
msg))
|
||||
self.warn(
|
||||
'%s, line %d: %s' % (
|
||||
template.filename,
|
||||
template.current_line,
|
||||
msg,
|
||||
),
|
||||
)
|
||||
finally:
|
||||
template.close()
|
||||
|
||||
|
|
@ -369,9 +422,11 @@ class sdist(Command):
|
|||
else:
|
||||
seps = '/'
|
||||
|
||||
vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr',
|
||||
'_darcs']
|
||||
vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps)
|
||||
vcs_dirs = [
|
||||
'RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr',
|
||||
'_darcs',
|
||||
]
|
||||
vcs_ptrn = r'(^|{})({})({}).*'.format(seps, '|'.join(vcs_dirs), seps)
|
||||
self.filelist.exclude_pattern(vcs_ptrn, is_regex=1)
|
||||
|
||||
def write_manifest(self):
|
||||
|
|
@ -380,14 +435,18 @@ class sdist(Command):
|
|||
named by 'self.manifest'.
|
||||
"""
|
||||
if self._manifest_is_not_generated():
|
||||
log.info("not writing to manually maintained "
|
||||
"manifest file '%s'" % self.manifest)
|
||||
log.info(
|
||||
'not writing to manually maintained '
|
||||
"manifest file '%s'" % self.manifest,
|
||||
)
|
||||
return
|
||||
|
||||
content = self.filelist.files[:]
|
||||
content.insert(0, '# file GENERATED by distutils, do NOT edit')
|
||||
self.execute(file_util.write_file, (self.manifest, content),
|
||||
"writing manifest file '%s'" % self.manifest)
|
||||
self.execute(
|
||||
file_util.write_file, (self.manifest, content),
|
||||
"writing manifest file '%s'" % self.manifest,
|
||||
)
|
||||
|
||||
def _manifest_is_not_generated(self):
|
||||
# check for special comment used in 3.1.3 and higher
|
||||
|
|
@ -439,13 +498,13 @@ class sdist(Command):
|
|||
|
||||
if hasattr(os, 'link'): # can make hard links on this system
|
||||
link = 'hard'
|
||||
msg = "making hard links in %s..." % base_dir
|
||||
msg = 'making hard links in %s...' % base_dir
|
||||
else: # nope, have to copy
|
||||
link = None
|
||||
msg = "copying files to %s..." % base_dir
|
||||
msg = 'copying files to %s...' % base_dir
|
||||
|
||||
if not files:
|
||||
log.warn("no files to distribute -- empty manifest?")
|
||||
log.warn('no files to distribute -- empty manifest?')
|
||||
else:
|
||||
log.info(msg)
|
||||
for file in files:
|
||||
|
|
@ -477,8 +536,10 @@ class sdist(Command):
|
|||
self.formats.append(self.formats.pop(self.formats.index('tar')))
|
||||
|
||||
for fmt in self.formats:
|
||||
file = self.make_archive(base_name, fmt, base_dir=base_dir,
|
||||
owner=self.owner, group=self.group)
|
||||
file = self.make_archive(
|
||||
base_name, fmt, base_dir=base_dir,
|
||||
owner=self.owner, group=self.group,
|
||||
)
|
||||
archive_files.append(file)
|
||||
self.distribution.dist_files.append(('sdist', '', file))
|
||||
|
||||
|
|
|
|||
|
|
@ -4,37 +4,44 @@ distutils.command.upload
|
|||
Implements the Distutils 'upload' subcommand (upload package to a package
|
||||
index).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import io
|
||||
import hashlib
|
||||
import io
|
||||
import os
|
||||
from base64 import standard_b64encode
|
||||
from urllib.request import urlopen, Request, HTTPError
|
||||
from urllib.parse import urlparse
|
||||
from distutils.errors import DistutilsError, DistutilsOptionError
|
||||
from distutils.core import PyPIRCCommand
|
||||
from distutils.spawn import spawn
|
||||
from urllib.request import HTTPError
|
||||
from urllib.request import Request
|
||||
from urllib.request import urlopen
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import PyPIRCCommand
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.spawn import spawn
|
||||
|
||||
|
||||
# PyPI Warehouse supports MD5, SHA256, and Blake2 (blake2-256)
|
||||
# https://bugs.python.org/issue40698
|
||||
_FILE_CONTENT_DIGESTS = {
|
||||
"md5_digest": getattr(hashlib, "md5", None),
|
||||
"sha256_digest": getattr(hashlib, "sha256", None),
|
||||
"blake2_256_digest": getattr(hashlib, "blake2b", None),
|
||||
'md5_digest': getattr(hashlib, 'md5', None),
|
||||
'sha256_digest': getattr(hashlib, 'sha256', None),
|
||||
'blake2_256_digest': getattr(hashlib, 'blake2b', None),
|
||||
}
|
||||
|
||||
|
||||
class upload(PyPIRCCommand):
|
||||
|
||||
description = "upload binary package to PyPI"
|
||||
description = 'upload binary package to PyPI'
|
||||
|
||||
user_options = PyPIRCCommand.user_options + [
|
||||
('sign', 's',
|
||||
'sign files to upload using gpg'),
|
||||
(
|
||||
'sign', 's',
|
||||
'sign files to upload using gpg',
|
||||
),
|
||||
('identity=', 'i', 'GPG identity used to sign files'),
|
||||
]
|
||||
]
|
||||
|
||||
boolean_options = PyPIRCCommand.boolean_options + ['sign']
|
||||
|
||||
|
|
@ -50,7 +57,7 @@ class upload(PyPIRCCommand):
|
|||
PyPIRCCommand.finalize_options(self)
|
||||
if self.identity and not self.sign:
|
||||
raise DistutilsOptionError(
|
||||
"Must use --sign for --identity to have meaning"
|
||||
'Must use --sign for --identity to have meaning',
|
||||
)
|
||||
config = self._read_pypirc()
|
||||
if config != {}:
|
||||
|
|
@ -66,8 +73,10 @@ class upload(PyPIRCCommand):
|
|||
|
||||
def run(self):
|
||||
if not self.distribution.dist_files:
|
||||
msg = ("Must create and upload files in one command "
|
||||
"(e.g. setup.py sdist upload)")
|
||||
msg = (
|
||||
'Must create and upload files in one command '
|
||||
'(e.g. setup.py sdist upload)'
|
||||
)
|
||||
raise DistutilsOptionError(msg)
|
||||
for command, pyversion, filename in self.distribution.dist_files:
|
||||
self.upload_file(command, pyversion, filename)
|
||||
|
|
@ -77,22 +86,24 @@ class upload(PyPIRCCommand):
|
|||
schema, netloc, url, params, query, fragments = \
|
||||
urlparse(self.repository)
|
||||
if params or query or fragments:
|
||||
raise AssertionError("Incompatible url %s" % self.repository)
|
||||
raise AssertionError('Incompatible url %s' % self.repository)
|
||||
|
||||
if schema not in ('http', 'https'):
|
||||
raise AssertionError("unsupported schema " + schema)
|
||||
raise AssertionError('unsupported schema ' + schema)
|
||||
|
||||
# Sign if requested
|
||||
if self.sign:
|
||||
gpg_args = ["gpg", "--detach-sign", "-a", filename]
|
||||
gpg_args = ['gpg', '--detach-sign', '-a', filename]
|
||||
if self.identity:
|
||||
gpg_args[2:2] = ["--local-user", self.identity]
|
||||
spawn(gpg_args,
|
||||
dry_run=self.dry_run)
|
||||
gpg_args[2:2] = ['--local-user', self.identity]
|
||||
spawn(
|
||||
gpg_args,
|
||||
dry_run=self.dry_run,
|
||||
)
|
||||
|
||||
# Fill in the data - send all the meta-data in case we need to
|
||||
# register a new release
|
||||
f = open(filename,'rb')
|
||||
f = open(filename, 'rb')
|
||||
try:
|
||||
content = f.read()
|
||||
finally:
|
||||
|
|
@ -109,7 +120,7 @@ class upload(PyPIRCCommand):
|
|||
'version': meta.get_version(),
|
||||
|
||||
# file content
|
||||
'content': (os.path.basename(filename),content),
|
||||
'content': (os.path.basename(filename), content),
|
||||
'filetype': command,
|
||||
'pyversion': pyversion,
|
||||
|
||||
|
|
@ -129,7 +140,7 @@ class upload(PyPIRCCommand):
|
|||
'provides': meta.get_provides(),
|
||||
'requires': meta.get_requires(),
|
||||
'obsoletes': meta.get_obsoletes(),
|
||||
}
|
||||
}
|
||||
|
||||
data['comment'] = ''
|
||||
|
||||
|
|
@ -144,15 +155,17 @@ class upload(PyPIRCCommand):
|
|||
pass
|
||||
|
||||
if self.sign:
|
||||
with open(filename + ".asc", "rb") as f:
|
||||
data['gpg_signature'] = (os.path.basename(filename) + ".asc",
|
||||
f.read())
|
||||
with open(filename + '.asc', 'rb') as f:
|
||||
data['gpg_signature'] = (
|
||||
os.path.basename(filename) + '.asc',
|
||||
f.read(),
|
||||
)
|
||||
|
||||
# set up the authentication
|
||||
user_pass = (self.username + ":" + self.password).encode('ascii')
|
||||
user_pass = (self.username + ':' + self.password).encode('ascii')
|
||||
# The exact encoding of the authentication string is debated.
|
||||
# Anyway PyPI only accepts ascii for both username or password.
|
||||
auth = "Basic " + standard_b64encode(user_pass).decode('ascii')
|
||||
auth = 'Basic ' + standard_b64encode(user_pass).decode('ascii')
|
||||
|
||||
# Build up the MIME payload for the POST data
|
||||
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
|
|
@ -172,12 +185,12 @@ class upload(PyPIRCCommand):
|
|||
value = str(value).encode('utf-8')
|
||||
body.write(sep_boundary)
|
||||
body.write(title.encode('utf-8'))
|
||||
body.write(b"\r\n\r\n")
|
||||
body.write(b'\r\n\r\n')
|
||||
body.write(value)
|
||||
body.write(end_boundary)
|
||||
body = body.getvalue()
|
||||
|
||||
msg = "Submitting %s to %s" % (filename, self.repository)
|
||||
msg = 'Submitting {} to {}'.format(filename, self.repository)
|
||||
self.announce(msg, log.INFO)
|
||||
|
||||
# build the Request
|
||||
|
|
@ -187,8 +200,10 @@ class upload(PyPIRCCommand):
|
|||
'Authorization': auth,
|
||||
}
|
||||
|
||||
request = Request(self.repository, data=body,
|
||||
headers=headers)
|
||||
request = Request(
|
||||
self.repository, data=body,
|
||||
headers=headers,
|
||||
)
|
||||
# send the data
|
||||
try:
|
||||
result = urlopen(request)
|
||||
|
|
@ -202,13 +217,15 @@ class upload(PyPIRCCommand):
|
|||
raise
|
||||
|
||||
if status == 200:
|
||||
self.announce('Server response (%s): %s' % (status, reason),
|
||||
log.INFO)
|
||||
self.announce(
|
||||
'Server response ({}): {}'.format(status, reason),
|
||||
log.INFO,
|
||||
)
|
||||
if self.show_response:
|
||||
text = self._read_pypi_response(result)
|
||||
msg = '\n'.join(('-' * 75, text, '-' * 75))
|
||||
self.announce(msg, log.INFO)
|
||||
else:
|
||||
msg = 'Upload failed (%s): %s' % (status, reason)
|
||||
msg = 'Upload failed ({}): {}'.format(status, reason)
|
||||
self.announce(msg, log.ERROR)
|
||||
raise DistutilsError(msg)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
Provides the PyPIRCCommand class, the base class for the command classes
|
||||
that uses .pypirc in the distutils.command package.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from configparser import RawConfigParser
|
||||
|
||||
|
|
@ -18,6 +20,7 @@ username:%s
|
|||
password:%s
|
||||
"""
|
||||
|
||||
|
||||
class PyPIRCCommand(Command):
|
||||
"""Base command that knows how to handle the .pypirc file
|
||||
"""
|
||||
|
|
@ -27,11 +30,16 @@ class PyPIRCCommand(Command):
|
|||
realm = None
|
||||
|
||||
user_options = [
|
||||
('repository=', 'r',
|
||||
"url of repository [default: %s]" % \
|
||||
DEFAULT_REPOSITORY),
|
||||
('show-response', None,
|
||||
'display full response text from server')]
|
||||
(
|
||||
'repository=', 'r',
|
||||
'url of repository [default: %s]' %
|
||||
DEFAULT_REPOSITORY,
|
||||
),
|
||||
(
|
||||
'show-response', None,
|
||||
'display full response text from server',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = ['show-response']
|
||||
|
||||
|
|
@ -58,9 +66,11 @@ class PyPIRCCommand(Command):
|
|||
if 'distutils' in sections:
|
||||
# let's get the list of servers
|
||||
index_servers = config.get('distutils', 'index-servers')
|
||||
_servers = [server.strip() for server in
|
||||
index_servers.split('\n')
|
||||
if server.strip() != '']
|
||||
_servers = [
|
||||
server.strip() for server in
|
||||
index_servers.split('\n')
|
||||
if server.strip() != ''
|
||||
]
|
||||
if _servers == []:
|
||||
# nothing set, let's try to get the default pypi
|
||||
if 'pypi' in sections:
|
||||
|
|
@ -74,10 +84,14 @@ class PyPIRCCommand(Command):
|
|||
current['username'] = config.get(server, 'username')
|
||||
|
||||
# optional params
|
||||
for key, default in (('repository',
|
||||
self.DEFAULT_REPOSITORY),
|
||||
('realm', self.DEFAULT_REALM),
|
||||
('password', None)):
|
||||
for key, default in (
|
||||
(
|
||||
'repository',
|
||||
self.DEFAULT_REPOSITORY,
|
||||
),
|
||||
('realm', self.DEFAULT_REALM),
|
||||
('password', None),
|
||||
):
|
||||
if config.has_option(server, key):
|
||||
current[key] = config.get(server, key)
|
||||
else:
|
||||
|
|
@ -86,13 +100,17 @@ class PyPIRCCommand(Command):
|
|||
# work around people having "repository" for the "pypi"
|
||||
# section of their config set to the HTTP (rather than
|
||||
# HTTPS) URL
|
||||
if (server == 'pypi' and
|
||||
repository in (self.DEFAULT_REPOSITORY, 'pypi')):
|
||||
if (
|
||||
server == 'pypi' and
|
||||
repository in (self.DEFAULT_REPOSITORY, 'pypi')
|
||||
):
|
||||
current['repository'] = self.DEFAULT_REPOSITORY
|
||||
return current
|
||||
|
||||
if (current['server'] == repository or
|
||||
current['repository'] == repository):
|
||||
if (
|
||||
current['server'] == repository or
|
||||
current['repository'] == repository
|
||||
):
|
||||
return current
|
||||
elif 'server-login' in sections:
|
||||
# old format
|
||||
|
|
@ -101,11 +119,13 @@ class PyPIRCCommand(Command):
|
|||
repository = config.get(server, 'repository')
|
||||
else:
|
||||
repository = self.DEFAULT_REPOSITORY
|
||||
return {'username': config.get(server, 'username'),
|
||||
'password': config.get(server, 'password'),
|
||||
'repository': repository,
|
||||
'server': server,
|
||||
'realm': self.DEFAULT_REALM}
|
||||
return {
|
||||
'username': config.get(server, 'username'),
|
||||
'password': config.get(server, 'password'),
|
||||
'repository': repository,
|
||||
'server': server,
|
||||
'realm': self.DEFAULT_REALM,
|
||||
}
|
||||
|
||||
return {}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,18 +5,18 @@ the 'setup' function (which is to be called from the setup script). Also
|
|||
indirectly provides the Distribution and Command classes, although they are
|
||||
really defined in distutils.dist and distutils.cmd.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from distutils.debug import DEBUG
|
||||
from distutils.errors import *
|
||||
|
||||
# Mainly import these so setup scripts can "from distutils.core import" them.
|
||||
from distutils.dist import Distribution
|
||||
from distutils.cmd import Command
|
||||
from distutils.config import PyPIRCCommand
|
||||
from distutils.debug import DEBUG
|
||||
from distutils.dist import Distribution
|
||||
from distutils.errors import *
|
||||
from distutils.extension import Extension
|
||||
# Mainly import these so setup scripts can "from distutils.core import" them.
|
||||
|
||||
# This is a barebones help message generated displayed when the user
|
||||
# runs the setup script with no arguments at all. More useful help
|
||||
|
|
@ -29,7 +29,8 @@ usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
|
|||
or: %(script)s cmd --help
|
||||
"""
|
||||
|
||||
def gen_usage (script_name):
|
||||
|
||||
def gen_usage(script_name):
|
||||
script = os.path.basename(script_name)
|
||||
return USAGE % vars()
|
||||
|
||||
|
|
@ -39,22 +40,26 @@ _setup_stop_after = None
|
|||
_setup_distribution = None
|
||||
|
||||
# Legal keyword arguments for the setup() function
|
||||
setup_keywords = ('distclass', 'script_name', 'script_args', 'options',
|
||||
'name', 'version', 'author', 'author_email',
|
||||
'maintainer', 'maintainer_email', 'url', 'license',
|
||||
'description', 'long_description', 'keywords',
|
||||
'platforms', 'classifiers', 'download_url',
|
||||
'requires', 'provides', 'obsoletes',
|
||||
)
|
||||
setup_keywords = (
|
||||
'distclass', 'script_name', 'script_args', 'options',
|
||||
'name', 'version', 'author', 'author_email',
|
||||
'maintainer', 'maintainer_email', 'url', 'license',
|
||||
'description', 'long_description', 'keywords',
|
||||
'platforms', 'classifiers', 'download_url',
|
||||
'requires', 'provides', 'obsoletes',
|
||||
)
|
||||
|
||||
# Legal keyword arguments for the Extension constructor
|
||||
extension_keywords = ('name', 'sources', 'include_dirs',
|
||||
'define_macros', 'undef_macros',
|
||||
'library_dirs', 'libraries', 'runtime_library_dirs',
|
||||
'extra_objects', 'extra_compile_args', 'extra_link_args',
|
||||
'swig_opts', 'export_symbols', 'depends', 'language')
|
||||
extension_keywords = (
|
||||
'name', 'sources', 'include_dirs',
|
||||
'define_macros', 'undef_macros',
|
||||
'library_dirs', 'libraries', 'runtime_library_dirs',
|
||||
'extra_objects', 'extra_compile_args', 'extra_link_args',
|
||||
'swig_opts', 'export_symbols', 'depends', 'language',
|
||||
)
|
||||
|
||||
def setup (**attrs):
|
||||
|
||||
def setup(**attrs):
|
||||
"""The gateway to the Distutils: do everything your setup script needs
|
||||
to do, in a highly flexible and user-driven way. Briefly: create a
|
||||
Distribution instance; find and parse config files; parse the command
|
||||
|
|
@ -99,7 +104,7 @@ def setup (**attrs):
|
|||
|
||||
if 'script_name' not in attrs:
|
||||
attrs['script_name'] = os.path.basename(sys.argv[0])
|
||||
if 'script_args' not in attrs:
|
||||
if 'script_args' not in attrs:
|
||||
attrs['script_args'] = sys.argv[1:]
|
||||
|
||||
# Create the Distribution instance, using the remaining arguments
|
||||
|
|
@ -108,12 +113,14 @@ def setup (**attrs):
|
|||
_setup_distribution = dist = klass(attrs)
|
||||
except DistutilsSetupError as msg:
|
||||
if 'name' not in attrs:
|
||||
raise SystemExit("error in setup command: %s" % msg)
|
||||
raise SystemExit('error in setup command: %s' % msg)
|
||||
else:
|
||||
raise SystemExit("error in %s setup command: %s" % \
|
||||
(attrs['name'], msg))
|
||||
raise SystemExit(
|
||||
'error in %s setup command: %s' %
|
||||
(attrs['name'], msg),
|
||||
)
|
||||
|
||||
if _setup_stop_after == "init":
|
||||
if _setup_stop_after == 'init':
|
||||
return dist
|
||||
|
||||
# Find and parse the config file(s): they will override options from
|
||||
|
|
@ -121,10 +128,10 @@ def setup (**attrs):
|
|||
dist.parse_config_files()
|
||||
|
||||
if DEBUG:
|
||||
print("options (after parsing config files):")
|
||||
print('options (after parsing config files):')
|
||||
dist.dump_option_dicts()
|
||||
|
||||
if _setup_stop_after == "config":
|
||||
if _setup_stop_after == 'config':
|
||||
return dist
|
||||
|
||||
# Parse the command line and override config files; any
|
||||
|
|
@ -133,13 +140,13 @@ def setup (**attrs):
|
|||
try:
|
||||
ok = dist.parse_command_line()
|
||||
except DistutilsArgError as msg:
|
||||
raise SystemExit(gen_usage(dist.script_name) + "\nerror: %s" % msg)
|
||||
raise SystemExit(gen_usage(dist.script_name) + '\nerror: %s' % msg)
|
||||
|
||||
if DEBUG:
|
||||
print("options (after parsing command line):")
|
||||
print('options (after parsing command line):')
|
||||
dist.dump_option_dicts()
|
||||
|
||||
if _setup_stop_after == "commandline":
|
||||
if _setup_stop_after == 'commandline':
|
||||
return dist
|
||||
|
||||
# And finally, run all the commands found on the command line.
|
||||
|
|
@ -147,27 +154,29 @@ def setup (**attrs):
|
|||
try:
|
||||
dist.run_commands()
|
||||
except KeyboardInterrupt:
|
||||
raise SystemExit("interrupted")
|
||||
raise SystemExit('interrupted')
|
||||
except OSError as exc:
|
||||
if DEBUG:
|
||||
sys.stderr.write("error: %s\n" % (exc,))
|
||||
sys.stderr.write('error: {}\n'.format(exc))
|
||||
raise
|
||||
else:
|
||||
raise SystemExit("error: %s" % (exc,))
|
||||
raise SystemExit('error: {}'.format(exc))
|
||||
|
||||
except (DistutilsError,
|
||||
CCompilerError) as msg:
|
||||
except (
|
||||
DistutilsError,
|
||||
CCompilerError,
|
||||
) as msg:
|
||||
if DEBUG:
|
||||
raise
|
||||
else:
|
||||
raise SystemExit("error: " + str(msg))
|
||||
raise SystemExit('error: ' + str(msg))
|
||||
|
||||
return dist
|
||||
|
||||
# setup ()
|
||||
|
||||
|
||||
def run_setup (script_name, script_args=None, stop_after="run"):
|
||||
def run_setup(script_name, script_args=None, stop_after='run'):
|
||||
"""Run a setup script in a somewhat controlled environment, and
|
||||
return the Distribution instance that drives things. This is useful
|
||||
if you need to find out the distribution meta-data (passed as
|
||||
|
|
@ -199,7 +208,7 @@ def run_setup (script_name, script_args=None, stop_after="run"):
|
|||
used to drive the Distutils.
|
||||
"""
|
||||
if stop_after not in ('init', 'config', 'commandline', 'run'):
|
||||
raise ValueError("invalid value for 'stop_after': %r" % (stop_after,))
|
||||
raise ValueError("invalid value for 'stop_after': {!r}".format(stop_after))
|
||||
|
||||
global _setup_stop_after, _setup_distribution
|
||||
_setup_stop_after = stop_after
|
||||
|
|
@ -222,9 +231,13 @@ def run_setup (script_name, script_args=None, stop_after="run"):
|
|||
pass
|
||||
|
||||
if _setup_distribution is None:
|
||||
raise RuntimeError(("'distutils.core.setup()' was never called -- "
|
||||
"perhaps '%s' is not a Distutils setup script?") % \
|
||||
script_name)
|
||||
raise RuntimeError(
|
||||
(
|
||||
"'distutils.core.setup()' was never called -- "
|
||||
"perhaps '%s' is not a Distutils setup script?"
|
||||
) %
|
||||
script_name,
|
||||
)
|
||||
|
||||
# I wonder if the setup script's namespace -- g and l -- would be of
|
||||
# any interest to callers?
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ handles the Cygwin port of the GNU C compiler to Windows. It also contains
|
|||
the Mingw32CCompiler class which handles the mingw32 port of GCC (same as
|
||||
cygwin in no-cygwin mode).
|
||||
"""
|
||||
|
||||
# problems:
|
||||
#
|
||||
# * if you use a msvc compiled python version (1.5.2)
|
||||
|
|
@ -46,19 +45,25 @@ cygwin in no-cygwin mode).
|
|||
# (ld supports -shared)
|
||||
# * llvm-mingw with Clang 11 works
|
||||
# (lld supports -shared)
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import copy
|
||||
from subprocess import Popen, PIPE, check_output
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from subprocess import check_output
|
||||
from subprocess import PIPE
|
||||
from subprocess import Popen
|
||||
|
||||
from distutils.unixccompiler import UnixCCompiler
|
||||
from distutils.errors import CCompilerError
|
||||
from distutils.errors import CompileError
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.errors import UnknownFileError
|
||||
from distutils.file_util import write_file
|
||||
from distutils.errors import (DistutilsExecError, CCompilerError,
|
||||
CompileError, UnknownFileError)
|
||||
from distutils.version import LooseVersion
|
||||
from distutils.spawn import find_executable
|
||||
from distutils.unixccompiler import UnixCCompiler
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
|
||||
def get_msvcr():
|
||||
"""Include the appropriate MSVC runtime library if Python was built
|
||||
|
|
@ -66,7 +71,7 @@ def get_msvcr():
|
|||
"""
|
||||
msc_pos = sys.version.find('MSC v.')
|
||||
if msc_pos != -1:
|
||||
msc_ver = sys.version[msc_pos+6:msc_pos+10]
|
||||
msc_ver = sys.version[msc_pos + 6:msc_pos + 10]
|
||||
if msc_ver == '1300':
|
||||
# MSVC 7.0
|
||||
return ['msvcr70']
|
||||
|
|
@ -83,79 +88,90 @@ def get_msvcr():
|
|||
# VS2010 / MSVC 10.0
|
||||
return ['msvcr100']
|
||||
else:
|
||||
raise ValueError("Unknown MS Compiler version %s " % msc_ver)
|
||||
raise ValueError('Unknown MS Compiler version %s ' % msc_ver)
|
||||
|
||||
|
||||
class CygwinCCompiler(UnixCCompiler):
|
||||
""" Handles the Cygwin port of the GNU C compiler to Windows.
|
||||
"""
|
||||
compiler_type = 'cygwin'
|
||||
obj_extension = ".o"
|
||||
static_lib_extension = ".a"
|
||||
shared_lib_extension = ".dll"
|
||||
static_lib_format = "lib%s%s"
|
||||
shared_lib_format = "%s%s"
|
||||
exe_extension = ".exe"
|
||||
obj_extension = '.o'
|
||||
static_lib_extension = '.a'
|
||||
shared_lib_extension = '.dll'
|
||||
static_lib_format = 'lib%s%s'
|
||||
shared_lib_format = '%s%s'
|
||||
exe_extension = '.exe'
|
||||
|
||||
def __init__(self, verbose=0, dry_run=0, force=0):
|
||||
|
||||
UnixCCompiler.__init__(self, verbose, dry_run, force)
|
||||
|
||||
status, details = check_config_h()
|
||||
self.debug_print("Python's GCC status: %s (details: %s)" %
|
||||
(status, details))
|
||||
self.debug_print(
|
||||
"Python's GCC status: %s (details: %s)" %
|
||||
(status, details),
|
||||
)
|
||||
if status is not CONFIG_H_OK:
|
||||
self.warn(
|
||||
"Python's pyconfig.h doesn't seem to support your compiler. "
|
||||
"Reason: %s. "
|
||||
"Compiling may fail because of undefined preprocessor macros."
|
||||
% details)
|
||||
'Reason: %s. '
|
||||
'Compiling may fail because of undefined preprocessor macros.'
|
||||
% details,
|
||||
)
|
||||
|
||||
self.cc = os.environ.get('CC', 'gcc')
|
||||
self.cxx = os.environ.get('CXX', 'g++')
|
||||
|
||||
if ('gcc' in self.cc): # Start gcc workaround
|
||||
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) )
|
||||
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":
|
||||
if self.ld_version >= '2.10.90':
|
||||
self.linker_dll = self.cc
|
||||
else:
|
||||
self.linker_dll = "dllwrap"
|
||||
self.linker_dll = 'dllwrap'
|
||||
|
||||
# ld_version >= "2.13" support -shared so use it instead of
|
||||
# -mdll -static
|
||||
if self.ld_version >= "2.13":
|
||||
shared_option = "-shared"
|
||||
if self.ld_version >= '2.13':
|
||||
shared_option = '-shared'
|
||||
else:
|
||||
shared_option = "-mdll -static"
|
||||
else: # Assume linker is up to date
|
||||
shared_option = '-mdll -static'
|
||||
else: # Assume linker is up to date
|
||||
self.linker_dll = self.cc
|
||||
shared_option = "-shared"
|
||||
shared_option = '-shared'
|
||||
|
||||
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)))
|
||||
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 ('gcc' in self.cc and 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"]
|
||||
self.dll_libraries = ['msvcrt']
|
||||
self.warn(
|
||||
"Consider upgrading to a newer version of gcc")
|
||||
'Consider upgrading to a newer version of gcc',
|
||||
)
|
||||
else:
|
||||
# Include the appropriate MSVC runtime library if Python was built
|
||||
# with MSVC 7.0 or later.
|
||||
|
|
@ -166,20 +182,24 @@ class CygwinCCompiler(UnixCCompiler):
|
|||
if ext == '.rc' or ext == '.res':
|
||||
# gcc needs '.res' and '.rc' compiled to object files !!!
|
||||
try:
|
||||
self.spawn(["windres", "-i", src, "-o", obj])
|
||||
self.spawn(['windres', '-i', src, '-o', obj])
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
else: # for other files use the C-compiler
|
||||
else: # for other files use the C-compiler
|
||||
try:
|
||||
self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
|
||||
extra_postargs)
|
||||
self.spawn(
|
||||
self.compiler_so + cc_args + [src, '-o', obj] +
|
||||
extra_postargs,
|
||||
)
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
|
||||
def link(self, target_desc, objects, output_filename, output_dir=None,
|
||||
libraries=None, library_dirs=None, runtime_library_dirs=None,
|
||||
export_symbols=None, debug=0, extra_preargs=None,
|
||||
extra_postargs=None, build_temp=None, target_lang=None):
|
||||
def link(
|
||||
self, target_desc, objects, output_filename, output_dir=None,
|
||||
libraries=None, library_dirs=None, runtime_library_dirs=None,
|
||||
export_symbols=None, debug=0, extra_preargs=None,
|
||||
extra_postargs=None, build_temp=None, target_lang=None,
|
||||
):
|
||||
"""Link the objects."""
|
||||
# use separate copies, so we can modify the lists
|
||||
extra_preargs = copy.copy(extra_preargs or [])
|
||||
|
|
@ -192,7 +212,7 @@ class CygwinCCompiler(UnixCCompiler):
|
|||
# handle export symbols by creating a def-file
|
||||
# with executables this only works with gcc/ld as linker
|
||||
if ((export_symbols is not None) and
|
||||
(target_desc != self.EXECUTABLE or self.linker_dll == "gcc")):
|
||||
(target_desc != self.EXECUTABLE or self.linker_dll == 'gcc')):
|
||||
# (The linker doesn't do anything if output is up-to-date.
|
||||
# So it would probably better to check if we really need this,
|
||||
# but for this we had to insert some unchanged parts of
|
||||
|
|
@ -204,28 +224,32 @@ class CygwinCCompiler(UnixCCompiler):
|
|||
temp_dir = os.path.dirname(objects[0])
|
||||
# name of dll to give the helper files the same base name
|
||||
(dll_name, dll_extension) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
os.path.basename(output_filename),
|
||||
)
|
||||
|
||||
# generate the filenames for these files
|
||||
def_file = os.path.join(temp_dir, dll_name + ".def")
|
||||
lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a")
|
||||
def_file = os.path.join(temp_dir, dll_name + '.def')
|
||||
lib_file = os.path.join(temp_dir, 'lib' + dll_name + '.a')
|
||||
|
||||
# Generate .def file
|
||||
contents = [
|
||||
"LIBRARY %s" % os.path.basename(output_filename),
|
||||
"EXPORTS"]
|
||||
'LIBRARY %s' % os.path.basename(output_filename),
|
||||
'EXPORTS',
|
||||
]
|
||||
for sym in export_symbols:
|
||||
contents.append(sym)
|
||||
self.execute(write_file, (def_file, contents),
|
||||
"writing %s" % def_file)
|
||||
self.execute(
|
||||
write_file, (def_file, contents),
|
||||
'writing %s' % def_file,
|
||||
)
|
||||
|
||||
# next add options for def-file and to creating import libraries
|
||||
|
||||
# dllwrap uses different options than gcc/ld
|
||||
if self.linker_dll == "dllwrap":
|
||||
extra_preargs.extend(["--output-lib", lib_file])
|
||||
if self.linker_dll == 'dllwrap':
|
||||
extra_preargs.extend(['--output-lib', lib_file])
|
||||
# for dllwrap we have to use a special option
|
||||
extra_preargs.extend(["--def", def_file])
|
||||
extra_preargs.extend(['--def', def_file])
|
||||
# we use gcc/ld here and can be sure ld is >= 2.9.10
|
||||
else:
|
||||
# doesn't work: bfd_close build\...\libfoo.a: Invalid operation
|
||||
|
|
@ -243,14 +267,16 @@ class CygwinCCompiler(UnixCCompiler):
|
|||
# unstripped_file = stripped_file + XXX KiB
|
||||
# ( XXX=254 for a typical python extension))
|
||||
if not debug:
|
||||
extra_preargs.append("-s")
|
||||
extra_preargs.append('-s')
|
||||
|
||||
UnixCCompiler.link(self, target_desc, objects, output_filename,
|
||||
output_dir, libraries, library_dirs,
|
||||
runtime_library_dirs,
|
||||
None, # export_symbols, we do this in our def-file
|
||||
debug, extra_preargs, extra_postargs, build_temp,
|
||||
target_lang)
|
||||
UnixCCompiler.link(
|
||||
self, target_desc, objects, output_filename,
|
||||
output_dir, libraries, library_dirs,
|
||||
runtime_library_dirs,
|
||||
None, # export_symbols, we do this in our def-file
|
||||
debug, extra_preargs, extra_postargs, build_temp,
|
||||
target_lang,
|
||||
)
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
|
||||
|
|
@ -262,21 +288,33 @@ class CygwinCCompiler(UnixCCompiler):
|
|||
for src_name in source_filenames:
|
||||
# use normcase to make sure '.rc' is really '.rc' and not '.RC'
|
||||
base, ext = os.path.splitext(os.path.normcase(src_name))
|
||||
if ext not in (self.src_extensions + ['.rc','.res']):
|
||||
raise UnknownFileError("unknown file type '%s' (from '%s')" % \
|
||||
(ext, src_name))
|
||||
if ext not in (self.src_extensions + ['.rc', '.res']):
|
||||
raise UnknownFileError(
|
||||
"unknown file type '%s' (from '%s')" %
|
||||
(ext, src_name),
|
||||
)
|
||||
if strip_dir:
|
||||
base = os.path.basename (base)
|
||||
base = os.path.basename(base)
|
||||
if ext in ('.res', '.rc'):
|
||||
# these need to be compiled to object files
|
||||
obj_names.append (os.path.join(output_dir,
|
||||
base + ext + self.obj_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + ext + self.obj_extension,
|
||||
),
|
||||
)
|
||||
else:
|
||||
obj_names.append (os.path.join(output_dir,
|
||||
base + self.obj_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.obj_extension,
|
||||
),
|
||||
)
|
||||
return obj_names
|
||||
|
||||
# the same as cygwin plus some additional parameters
|
||||
|
||||
|
||||
class Mingw32CCompiler(CygwinCCompiler):
|
||||
""" Handles the Mingw32 port of the GNU C compiler to Windows.
|
||||
"""
|
||||
|
|
@ -284,39 +322,44 @@ class Mingw32CCompiler(CygwinCCompiler):
|
|||
|
||||
def __init__(self, verbose=0, dry_run=0, force=0):
|
||||
|
||||
CygwinCCompiler.__init__ (self, verbose, dry_run, force)
|
||||
CygwinCCompiler.__init__(self, verbose, dry_run, force)
|
||||
|
||||
# ld_version >= "2.13" support -shared so use it instead of
|
||||
# -mdll -static
|
||||
if ('gcc' in self.cc and self.ld_version < "2.13"):
|
||||
shared_option = "-mdll -static"
|
||||
if ('gcc' in self.cc and self.ld_version < '2.13'):
|
||||
shared_option = '-mdll -static'
|
||||
else:
|
||||
shared_option = "-shared"
|
||||
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 ('gcc' in self.cc and 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_cygwincc(self.cc):
|
||||
raise CCompilerError(
|
||||
'Cygwin gcc cannot be used with --compiler=mingw32')
|
||||
'Cygwin gcc cannot be used with --compiler=mingw32',
|
||||
)
|
||||
|
||||
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))
|
||||
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,
|
||||
),
|
||||
)
|
||||
# Maybe we should also append -mthreads, but then the finished
|
||||
# dlls need another dll (mingwm10.dll see Mingw32 docs)
|
||||
# (-mthreads: Support thread-safe exception handling on `Mingw32')
|
||||
|
||||
# no additional libraries needed
|
||||
self.dll_libraries=[]
|
||||
self.dll_libraries = []
|
||||
|
||||
# Include the appropriate MSVC runtime library if Python was built
|
||||
# with MSVC 7.0 or later.
|
||||
|
|
@ -326,9 +369,11 @@ class Mingw32CCompiler(CygwinCCompiler):
|
|||
# default, we should at least warn the user if he is using an unmodified
|
||||
# version.
|
||||
|
||||
CONFIG_H_OK = "ok"
|
||||
CONFIG_H_NOTOK = "not ok"
|
||||
CONFIG_H_UNCERTAIN = "uncertain"
|
||||
|
||||
CONFIG_H_OK = 'ok'
|
||||
CONFIG_H_NOTOK = 'not ok'
|
||||
CONFIG_H_UNCERTAIN = 'uncertain'
|
||||
|
||||
|
||||
def check_config_h():
|
||||
"""Check if the current Python installation appears amenable to building
|
||||
|
|
@ -355,11 +400,11 @@ def check_config_h():
|
|||
|
||||
# if sys.version contains GCC then python was compiled with GCC, and the
|
||||
# pyconfig.h file should be OK
|
||||
if "GCC" in sys.version:
|
||||
if 'GCC' in sys.version:
|
||||
return CONFIG_H_OK, "sys.version mentions 'GCC'"
|
||||
|
||||
# Clang would also work
|
||||
if "Clang" in sys.version:
|
||||
if 'Clang' in sys.version:
|
||||
return CONFIG_H_OK, "sys.version mentions 'Clang'"
|
||||
|
||||
# let's see if __GNUC__ is mentioned in python.h
|
||||
|
|
@ -367,18 +412,22 @@ def check_config_h():
|
|||
try:
|
||||
config_h = open(fn)
|
||||
try:
|
||||
if "__GNUC__" in config_h.read():
|
||||
if '__GNUC__' in config_h.read():
|
||||
return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn
|
||||
else:
|
||||
return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn
|
||||
finally:
|
||||
config_h.close()
|
||||
except OSError as exc:
|
||||
return (CONFIG_H_UNCERTAIN,
|
||||
"couldn't read '%s': %s" % (fn, exc.strerror))
|
||||
return (
|
||||
CONFIG_H_UNCERTAIN,
|
||||
"couldn't read '{}': {}".format(fn, exc.strerror),
|
||||
)
|
||||
|
||||
|
||||
RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)')
|
||||
|
||||
|
||||
def _find_exe_version(cmd):
|
||||
"""Find the version of an executable by running `cmd` in the shell.
|
||||
|
||||
|
|
@ -400,6 +449,7 @@ def _find_exe_version(cmd):
|
|||
# so we need to decode our bytes
|
||||
return LooseVersion(result.group(1).decode())
|
||||
|
||||
|
||||
def get_versions():
|
||||
""" Try to find out the versions of gcc, ld and dllwrap.
|
||||
|
||||
|
|
@ -408,6 +458,7 @@ def get_versions():
|
|||
commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
|
||||
return tuple([_find_exe_version(cmd) for cmd in commands])
|
||||
|
||||
|
||||
def is_cygwincc(cc):
|
||||
'''Try to determine if the compiler that would be used is from cygwin.'''
|
||||
out_string = check_output([cc, '-dumpmachine'])
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
# If DISTUTILS_DEBUG is anything other than the empty string, we run in
|
||||
|
|
|
|||
|
|
@ -3,20 +3,24 @@
|
|||
Utility functions for simple, timestamp-based dependency of files
|
||||
and groups of files; also, function based entirely on such
|
||||
timestamp dependency analysis."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils.errors import DistutilsFileError
|
||||
|
||||
|
||||
def newer (source, target):
|
||||
def newer(source, target):
|
||||
"""Return true if 'source' exists and is more recently modified than
|
||||
'target', or if 'source' exists and 'target' doesn't. Return false if
|
||||
both exist and 'target' is the same age or younger than 'source'.
|
||||
Raise DistutilsFileError if 'source' does not exist.
|
||||
"""
|
||||
if not os.path.exists(source):
|
||||
raise DistutilsFileError("file '%s' does not exist" %
|
||||
os.path.abspath(source))
|
||||
raise DistutilsFileError(
|
||||
"file '%s' does not exist" %
|
||||
os.path.abspath(source),
|
||||
)
|
||||
if not os.path.exists(target):
|
||||
return 1
|
||||
|
||||
|
|
@ -29,7 +33,7 @@ def newer (source, target):
|
|||
# newer ()
|
||||
|
||||
|
||||
def newer_pairwise (sources, targets):
|
||||
def newer_pairwise(sources, targets):
|
||||
"""Walk two filename lists in parallel, testing if each source is newer
|
||||
than its corresponding target. Return a pair of lists (sources,
|
||||
targets) where source is newer than target, according to the semantics
|
||||
|
|
@ -51,7 +55,7 @@ def newer_pairwise (sources, targets):
|
|||
# newer_pairwise ()
|
||||
|
||||
|
||||
def newer_group (sources, target, missing='error'):
|
||||
def newer_group(sources, target, missing='error'):
|
||||
"""Return true if 'target' is out-of-date with respect to any file
|
||||
listed in 'sources'. In other words, if 'target' exists and is newer
|
||||
than every file in 'sources', return false; otherwise return true.
|
||||
|
|
@ -79,9 +83,9 @@ def newer_group (sources, target, missing='error'):
|
|||
if missing == 'error': # blow up when we stat() the file
|
||||
pass
|
||||
elif missing == 'ignore': # missing source dropped from
|
||||
continue # target's dependency list
|
||||
continue # target's dependency list
|
||||
elif missing == 'newer': # missing source means target is
|
||||
return 1 # out-of-date
|
||||
return 1 # out-of-date
|
||||
|
||||
source_mtime = os.stat(source)[ST_MTIME]
|
||||
if source_mtime > target_mtime:
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
"""distutils.dir_util
|
||||
|
||||
Utility functions for manipulating directories and directory trees."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import errno
|
||||
from distutils.errors import DistutilsFileError, DistutilsInternalError
|
||||
import os
|
||||
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsFileError
|
||||
from distutils.errors import DistutilsInternalError
|
||||
|
||||
# cache for by mkpath() -- in addition to cheapening redundant calls,
|
||||
# eliminates redundant "creating /foo/bar/baz" messages in dry-run mode
|
||||
|
|
@ -14,6 +17,8 @@ _path_created = {}
|
|||
# I don't use os.makedirs because a) it's new to Python 1.5.2, and
|
||||
# b) it blows up if the directory already exists (I want to silently
|
||||
# succeed in that case).
|
||||
|
||||
|
||||
def mkpath(name, mode=0o777, verbose=1, dry_run=0):
|
||||
"""Create a directory and any missing ancestor directories.
|
||||
|
||||
|
|
@ -30,7 +35,8 @@ def mkpath(name, mode=0o777, verbose=1, dry_run=0):
|
|||
# Detect a common bug -- name is None
|
||||
if not isinstance(name, str):
|
||||
raise DistutilsInternalError(
|
||||
"mkpath: 'name' must be a string (got %r)" % (name,))
|
||||
"mkpath: 'name' must be a string (got {!r})".format(name),
|
||||
)
|
||||
|
||||
# XXX what's the better way to handle verbosity? print as we create
|
||||
# each directory in the path (the current behaviour), or only announce
|
||||
|
|
@ -63,7 +69,7 @@ def mkpath(name, mode=0o777, verbose=1, dry_run=0):
|
|||
continue
|
||||
|
||||
if verbose >= 1:
|
||||
log.info("creating %s", head)
|
||||
log.info('creating %s', head)
|
||||
|
||||
if not dry_run:
|
||||
try:
|
||||
|
|
@ -71,12 +77,14 @@ def mkpath(name, mode=0o777, verbose=1, dry_run=0):
|
|||
except OSError as exc:
|
||||
if not (exc.errno == errno.EEXIST and os.path.isdir(head)):
|
||||
raise DistutilsFileError(
|
||||
"could not create '%s': %s" % (head, exc.args[-1]))
|
||||
"could not create '{}': {}".format(head, exc.args[-1]),
|
||||
)
|
||||
created_dirs.append(head)
|
||||
|
||||
_path_created[abs_head] = 1
|
||||
return created_dirs
|
||||
|
||||
|
||||
def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0):
|
||||
"""Create all the empty directories under 'base_dir' needed to put 'files'
|
||||
there.
|
||||
|
|
@ -96,8 +104,11 @@ def create_tree(base_dir, files, mode=0o777, verbose=1, dry_run=0):
|
|||
for dir in sorted(need_dir):
|
||||
mkpath(dir, mode, verbose=verbose, dry_run=dry_run)
|
||||
|
||||
def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
|
||||
preserve_symlinks=0, update=0, verbose=1, dry_run=0):
|
||||
|
||||
def copy_tree(
|
||||
src, dst, preserve_mode=1, preserve_times=1,
|
||||
preserve_symlinks=0, update=0, verbose=1, dry_run=0,
|
||||
):
|
||||
"""Copy an entire directory tree 'src' to a new location 'dst'.
|
||||
|
||||
Both 'src' and 'dst' must be directory names. If 'src' is not a
|
||||
|
|
@ -121,7 +132,8 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
|
|||
|
||||
if not dry_run and not os.path.isdir(src):
|
||||
raise DistutilsFileError(
|
||||
"cannot copy tree '%s': not a directory" % src)
|
||||
"cannot copy tree '%s': not a directory" % src,
|
||||
)
|
||||
try:
|
||||
names = os.listdir(src)
|
||||
except OSError as e:
|
||||
|
|
@ -129,7 +141,8 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
|
|||
names = []
|
||||
else:
|
||||
raise DistutilsFileError(
|
||||
"error listing files in '%s': %s" % (src, e.strerror))
|
||||
"error listing files in '{}': {}".format(src, e.strerror),
|
||||
)
|
||||
|
||||
if not dry_run:
|
||||
mkpath(dst, verbose=verbose)
|
||||
|
|
@ -147,34 +160,41 @@ def copy_tree(src, dst, preserve_mode=1, preserve_times=1,
|
|||
if preserve_symlinks and os.path.islink(src_name):
|
||||
link_dest = os.readlink(src_name)
|
||||
if verbose >= 1:
|
||||
log.info("linking %s -> %s", dst_name, link_dest)
|
||||
log.info('linking %s -> %s', dst_name, link_dest)
|
||||
if not dry_run:
|
||||
os.symlink(link_dest, dst_name)
|
||||
outputs.append(dst_name)
|
||||
|
||||
elif os.path.isdir(src_name):
|
||||
outputs.extend(
|
||||
copy_tree(src_name, dst_name, preserve_mode,
|
||||
preserve_times, preserve_symlinks, update,
|
||||
verbose=verbose, dry_run=dry_run))
|
||||
copy_tree(
|
||||
src_name, dst_name, preserve_mode,
|
||||
preserve_times, preserve_symlinks, update,
|
||||
verbose=verbose, dry_run=dry_run,
|
||||
),
|
||||
)
|
||||
else:
|
||||
copy_file(src_name, dst_name, preserve_mode,
|
||||
preserve_times, update, verbose=verbose,
|
||||
dry_run=dry_run)
|
||||
copy_file(
|
||||
src_name, dst_name, preserve_mode,
|
||||
preserve_times, update, verbose=verbose,
|
||||
dry_run=dry_run,
|
||||
)
|
||||
outputs.append(dst_name)
|
||||
|
||||
return outputs
|
||||
|
||||
|
||||
def _build_cmdtuple(path, cmdtuples):
|
||||
"""Helper for remove_tree()."""
|
||||
for f in os.listdir(path):
|
||||
real_f = os.path.join(path,f)
|
||||
real_f = os.path.join(path, f)
|
||||
if os.path.isdir(real_f) and not os.path.islink(real_f):
|
||||
_build_cmdtuple(real_f, cmdtuples)
|
||||
else:
|
||||
cmdtuples.append((os.remove, real_f))
|
||||
cmdtuples.append((os.rmdir, path))
|
||||
|
||||
|
||||
def remove_tree(directory, verbose=1, dry_run=0):
|
||||
"""Recursively remove an entire directory tree.
|
||||
|
||||
|
|
@ -197,7 +217,8 @@ def remove_tree(directory, verbose=1, dry_run=0):
|
|||
if abspath in _path_created:
|
||||
del _path_created[abspath]
|
||||
except OSError as exc:
|
||||
log.warn("error removing %s: %s", directory, exc)
|
||||
log.warn('error removing %s: %s', directory, exc)
|
||||
|
||||
|
||||
def ensure_relative(path):
|
||||
"""Take the full path 'path', and make it a relative path.
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
Provides the Distribution class, which represents the module distribution
|
||||
being built/installed/distributed.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from email import message_from_file
|
||||
|
||||
try:
|
||||
|
|
@ -65,12 +66,14 @@ class Distribution:
|
|||
# have minimal control over.
|
||||
# The fourth entry for verbose means that it can be repeated.
|
||||
global_options = [
|
||||
('verbose', 'v', "run verbosely (default)", 1),
|
||||
('quiet', 'q', "run quietly (turns verbosity off)"),
|
||||
('verbose', 'v', 'run verbosely (default)', 1),
|
||||
('quiet', 'q', 'run quietly (turns verbosity off)'),
|
||||
('dry-run', 'n', "don't actually do anything"),
|
||||
('help', 'h', "show detailed help message"),
|
||||
('no-user-cfg', None,
|
||||
'ignore pydistutils.cfg in your home directory'),
|
||||
('help', 'h', 'show detailed help message'),
|
||||
(
|
||||
'no-user-cfg', None,
|
||||
'ignore pydistutils.cfg in your home directory',
|
||||
),
|
||||
]
|
||||
|
||||
# 'common_usage' is a short (2-3 line) string describing the common
|
||||
|
|
@ -84,49 +87,91 @@ Common commands: (see '--help-commands' for more)
|
|||
|
||||
# options that are not propagated to the commands
|
||||
display_options = [
|
||||
('help-commands', None,
|
||||
"list all available commands"),
|
||||
('name', None,
|
||||
"print package name"),
|
||||
('version', 'V',
|
||||
"print package version"),
|
||||
('fullname', None,
|
||||
"print <package name>-<version>"),
|
||||
('author', None,
|
||||
"print the author's name"),
|
||||
('author-email', None,
|
||||
"print the author's email address"),
|
||||
('maintainer', None,
|
||||
"print the maintainer's name"),
|
||||
('maintainer-email', None,
|
||||
"print the maintainer's email address"),
|
||||
('contact', None,
|
||||
"print the maintainer's name if known, else the author's"),
|
||||
('contact-email', None,
|
||||
"print the maintainer's email address if known, else the author's"),
|
||||
('url', None,
|
||||
"print the URL for this package"),
|
||||
('license', None,
|
||||
"print the license of the package"),
|
||||
('licence', None,
|
||||
"alias for --license"),
|
||||
('description', None,
|
||||
"print the package description"),
|
||||
('long-description', None,
|
||||
"print the long package description"),
|
||||
('platforms', None,
|
||||
"print the list of platforms"),
|
||||
('classifiers', None,
|
||||
"print the list of classifiers"),
|
||||
('keywords', None,
|
||||
"print the list of keywords"),
|
||||
('provides', None,
|
||||
"print the list of packages/modules provided"),
|
||||
('requires', None,
|
||||
"print the list of packages/modules required"),
|
||||
('obsoletes', None,
|
||||
"print the list of packages/modules made obsolete")
|
||||
]
|
||||
(
|
||||
'help-commands', None,
|
||||
'list all available commands',
|
||||
),
|
||||
(
|
||||
'name', None,
|
||||
'print package name',
|
||||
),
|
||||
(
|
||||
'version', 'V',
|
||||
'print package version',
|
||||
),
|
||||
(
|
||||
'fullname', None,
|
||||
'print <package name>-<version>',
|
||||
),
|
||||
(
|
||||
'author', None,
|
||||
"print the author's name",
|
||||
),
|
||||
(
|
||||
'author-email', None,
|
||||
"print the author's email address",
|
||||
),
|
||||
(
|
||||
'maintainer', None,
|
||||
"print the maintainer's name",
|
||||
),
|
||||
(
|
||||
'maintainer-email', None,
|
||||
"print the maintainer's email address",
|
||||
),
|
||||
(
|
||||
'contact', None,
|
||||
"print the maintainer's name if known, else the author's",
|
||||
),
|
||||
(
|
||||
'contact-email', None,
|
||||
"print the maintainer's email address if known, else the author's",
|
||||
),
|
||||
(
|
||||
'url', None,
|
||||
'print the URL for this package',
|
||||
),
|
||||
(
|
||||
'license', None,
|
||||
'print the license of the package',
|
||||
),
|
||||
(
|
||||
'licence', None,
|
||||
'alias for --license',
|
||||
),
|
||||
(
|
||||
'description', None,
|
||||
'print the package description',
|
||||
),
|
||||
(
|
||||
'long-description', None,
|
||||
'print the long package description',
|
||||
),
|
||||
(
|
||||
'platforms', None,
|
||||
'print the list of platforms',
|
||||
),
|
||||
(
|
||||
'classifiers', None,
|
||||
'print the list of classifiers',
|
||||
),
|
||||
(
|
||||
'keywords', None,
|
||||
'print the list of keywords',
|
||||
),
|
||||
(
|
||||
'provides', None,
|
||||
'print the list of packages/modules provided',
|
||||
),
|
||||
(
|
||||
'requires', None,
|
||||
'print the list of packages/modules required',
|
||||
),
|
||||
(
|
||||
'obsoletes', None,
|
||||
'print the list of packages/modules made obsolete',
|
||||
),
|
||||
]
|
||||
display_option_names = [translate_longopt(x[0]) for x in display_options]
|
||||
|
||||
# negative options are options that exclude other options
|
||||
|
|
@ -159,7 +204,7 @@ Common commands: (see '--help-commands' for more)
|
|||
# object in a sneaky and underhanded (but efficient!) way.
|
||||
self.metadata = DistributionMetadata()
|
||||
for basename in self.metadata._METHOD_BASENAMES:
|
||||
method_name = "get_" + basename
|
||||
method_name = 'get_' + basename
|
||||
setattr(self, method_name, getattr(self.metadata, method_name))
|
||||
|
||||
# 'cmdclass' maps command names to class objects, so we
|
||||
|
|
@ -250,7 +295,7 @@ Common commands: (see '--help-commands' for more)
|
|||
for (command, cmd_options) in options.items():
|
||||
opt_dict = self.get_option_dict(command)
|
||||
for (opt, val) in cmd_options.items():
|
||||
opt_dict[opt] = ("setup script", val)
|
||||
opt_dict[opt] = ('setup script', val)
|
||||
|
||||
if 'licence' in attrs:
|
||||
attrs['license'] = attrs['licence']
|
||||
|
|
@ -259,19 +304,19 @@ Common commands: (see '--help-commands' for more)
|
|||
if warnings is not None:
|
||||
warnings.warn(msg)
|
||||
else:
|
||||
sys.stderr.write(msg + "\n")
|
||||
sys.stderr.write(msg + '\n')
|
||||
|
||||
# Now work on the rest of the attributes. Any attribute that's
|
||||
# not already defined is invalid!
|
||||
for (key, val) in attrs.items():
|
||||
if hasattr(self.metadata, "set_" + key):
|
||||
getattr(self.metadata, "set_" + key)(val)
|
||||
if hasattr(self.metadata, 'set_' + key):
|
||||
getattr(self.metadata, 'set_' + key)(val)
|
||||
elif hasattr(self.metadata, key):
|
||||
setattr(self.metadata, key, val)
|
||||
elif hasattr(self, key):
|
||||
setattr(self, key, val)
|
||||
else:
|
||||
msg = "Unknown distribution option: %s" % repr(key)
|
||||
msg = 'Unknown distribution option: %s' % repr(key)
|
||||
warnings.warn(msg)
|
||||
|
||||
# no-user-cfg is handled before other command line args
|
||||
|
|
@ -303,7 +348,7 @@ Common commands: (see '--help-commands' for more)
|
|||
dict = self.command_options[command] = {}
|
||||
return dict
|
||||
|
||||
def dump_option_dicts(self, header=None, commands=None, indent=""):
|
||||
def dump_option_dicts(self, header=None, commands=None, indent=''):
|
||||
from pprint import pformat
|
||||
|
||||
if commands is None: # dump all command option dicts
|
||||
|
|
@ -311,23 +356,27 @@ Common commands: (see '--help-commands' for more)
|
|||
|
||||
if header is not None:
|
||||
self.announce(indent + header)
|
||||
indent = indent + " "
|
||||
indent = indent + ' '
|
||||
|
||||
if not commands:
|
||||
self.announce(indent + "no commands known yet")
|
||||
self.announce(indent + 'no commands known yet')
|
||||
return
|
||||
|
||||
for cmd_name in commands:
|
||||
opt_dict = self.command_options.get(cmd_name)
|
||||
if opt_dict is None:
|
||||
self.announce(indent +
|
||||
"no option dict for '%s' command" % cmd_name)
|
||||
self.announce(
|
||||
indent +
|
||||
"no option dict for '%s' command" % cmd_name,
|
||||
)
|
||||
else:
|
||||
self.announce(indent +
|
||||
"option dict for '%s' command:" % cmd_name)
|
||||
self.announce(
|
||||
indent +
|
||||
"option dict for '%s' command:" % cmd_name,
|
||||
)
|
||||
out = pformat(opt_dict)
|
||||
for line in out.split('\n'):
|
||||
self.announce(indent + " " + line)
|
||||
self.announce(indent + ' ' + line)
|
||||
|
||||
# -- Config file finding/parsing methods ---------------------------
|
||||
|
||||
|
|
@ -353,15 +402,15 @@ Common commands: (see '--help-commands' for more)
|
|||
sys_dir = os.path.dirname(sys.modules['distutils'].__file__)
|
||||
|
||||
# Look for the system config file
|
||||
sys_file = os.path.join(sys_dir, "distutils.cfg")
|
||||
sys_file = os.path.join(sys_dir, 'distutils.cfg')
|
||||
if os.path.isfile(sys_file):
|
||||
files.append(sys_file)
|
||||
|
||||
# What to call the per-user config file
|
||||
if os.name == 'posix':
|
||||
user_filename = ".pydistutils.cfg"
|
||||
user_filename = '.pydistutils.cfg'
|
||||
else:
|
||||
user_filename = "pydistutils.cfg"
|
||||
user_filename = 'pydistutils.cfg'
|
||||
|
||||
# And look for the user config file
|
||||
if self.want_user_cfg:
|
||||
|
|
@ -370,12 +419,12 @@ Common commands: (see '--help-commands' for more)
|
|||
files.append(user_file)
|
||||
|
||||
# All platforms support local setup.cfg
|
||||
local_file = "setup.cfg"
|
||||
local_file = 'setup.cfg'
|
||||
if os.path.isfile(local_file):
|
||||
files.append(local_file)
|
||||
|
||||
if DEBUG:
|
||||
self.announce("using config files: %s" % ', '.join(files))
|
||||
self.announce('using config files: %s' % ', '.join(files))
|
||||
|
||||
return files
|
||||
|
||||
|
|
@ -388,7 +437,8 @@ Common commands: (see '--help-commands' for more)
|
|||
'install-base', 'install-platbase', 'install-lib',
|
||||
'install-platlib', 'install-purelib', 'install-headers',
|
||||
'install-scripts', 'install-data', 'prefix', 'exec-prefix',
|
||||
'home', 'user', 'root']
|
||||
'home', 'user', 'root',
|
||||
]
|
||||
else:
|
||||
ignore_options = []
|
||||
|
||||
|
|
@ -398,12 +448,12 @@ Common commands: (see '--help-commands' for more)
|
|||
filenames = self.find_config_files()
|
||||
|
||||
if DEBUG:
|
||||
self.announce("Distribution.parse_config_files():")
|
||||
self.announce('Distribution.parse_config_files():')
|
||||
|
||||
parser = ConfigParser()
|
||||
for filename in filenames:
|
||||
if DEBUG:
|
||||
self.announce(" reading %s" % filename)
|
||||
self.announce(' reading %s' % filename)
|
||||
parser.read(filename)
|
||||
for section in parser.sections():
|
||||
options = parser.options(section)
|
||||
|
|
@ -411,7 +461,7 @@ Common commands: (see '--help-commands' for more)
|
|||
|
||||
for opt in options:
|
||||
if opt != '__name__' and opt not in ignore_options:
|
||||
val = parser.get(section,opt)
|
||||
val = parser.get(section, opt)
|
||||
opt = opt.replace('-', '_')
|
||||
opt_dict[opt] = (filename, val)
|
||||
|
||||
|
|
@ -428,7 +478,7 @@ Common commands: (see '--help-commands' for more)
|
|||
try:
|
||||
if alias:
|
||||
setattr(self, alias, not strtobool(val))
|
||||
elif opt in ('verbose', 'dry_run'): # ugh!
|
||||
elif opt in ('verbose', 'dry_run'): # ugh!
|
||||
setattr(self, opt, strtobool(val))
|
||||
else:
|
||||
setattr(self, opt, val)
|
||||
|
|
@ -492,14 +542,16 @@ Common commands: (see '--help-commands' for more)
|
|||
# latter, we omit the display-only options and show help for
|
||||
# each command listed on the command line.
|
||||
if self.help:
|
||||
self._show_help(parser,
|
||||
display_options=len(self.commands) == 0,
|
||||
commands=self.commands)
|
||||
self._show_help(
|
||||
parser,
|
||||
display_options=len(self.commands) == 0,
|
||||
commands=self.commands,
|
||||
)
|
||||
return
|
||||
|
||||
# Oops, no commands found -- an end-user error
|
||||
if not self.commands:
|
||||
raise DistutilsArgError("no commands supplied")
|
||||
raise DistutilsArgError('no commands supplied')
|
||||
|
||||
# All is well: return true
|
||||
return True
|
||||
|
|
@ -511,9 +563,11 @@ Common commands: (see '--help-commands' for more)
|
|||
level as well as options recognized for commands.
|
||||
"""
|
||||
return self.global_options + [
|
||||
("command-packages=", None,
|
||||
"list of packages that provide distutils commands"),
|
||||
]
|
||||
(
|
||||
'command-packages=', None,
|
||||
'list of packages that provide distutils commands',
|
||||
),
|
||||
]
|
||||
|
||||
def _parse_command_opts(self, parser, args):
|
||||
"""Parse the command-line options for a single command.
|
||||
|
|
@ -545,14 +599,19 @@ Common commands: (see '--help-commands' for more)
|
|||
# to be sure that the basic "command" interface is implemented.
|
||||
if not issubclass(cmd_class, Command):
|
||||
raise DistutilsClassError(
|
||||
"command class %s must subclass Command" % cmd_class)
|
||||
'command class %s must subclass Command' % cmd_class,
|
||||
)
|
||||
|
||||
# Also make sure that the command object provides a list of its
|
||||
# known options.
|
||||
if not (hasattr(cmd_class, 'user_options') and
|
||||
isinstance(cmd_class.user_options, list)):
|
||||
msg = ("command class %s must provide "
|
||||
"'user_options' attribute (a list of tuples)")
|
||||
if not (
|
||||
hasattr(cmd_class, 'user_options') and
|
||||
isinstance(cmd_class.user_options, list)
|
||||
):
|
||||
msg = (
|
||||
'command class %s must provide '
|
||||
"'user_options' attribute (a list of tuples)"
|
||||
)
|
||||
raise DistutilsClassError(msg % cmd_class)
|
||||
|
||||
# If the command class has a list of negative alias options,
|
||||
|
|
@ -564,36 +623,43 @@ Common commands: (see '--help-commands' for more)
|
|||
|
||||
# Check for help_options in command class. They have a different
|
||||
# format (tuple of four) so we need to preprocess them here.
|
||||
if (hasattr(cmd_class, 'help_options') and
|
||||
isinstance(cmd_class.help_options, list)):
|
||||
if (
|
||||
hasattr(cmd_class, 'help_options') and
|
||||
isinstance(cmd_class.help_options, list)
|
||||
):
|
||||
help_options = fix_help_options(cmd_class.help_options)
|
||||
else:
|
||||
help_options = []
|
||||
|
||||
# All commands support the global options too, just by adding
|
||||
# in 'global_options'.
|
||||
parser.set_option_table(self.global_options +
|
||||
cmd_class.user_options +
|
||||
help_options)
|
||||
parser.set_option_table(
|
||||
self.global_options +
|
||||
cmd_class.user_options +
|
||||
help_options,
|
||||
)
|
||||
parser.set_negative_aliases(negative_opt)
|
||||
(args, opts) = parser.getopt(args[1:])
|
||||
if hasattr(opts, 'help') and opts.help:
|
||||
self._show_help(parser, display_options=0, commands=[cmd_class])
|
||||
return
|
||||
|
||||
if (hasattr(cmd_class, 'help_options') and
|
||||
isinstance(cmd_class.help_options, list)):
|
||||
help_option_found=0
|
||||
if (
|
||||
hasattr(cmd_class, 'help_options') and
|
||||
isinstance(cmd_class.help_options, list)
|
||||
):
|
||||
help_option_found = 0
|
||||
for (help_option, short, desc, func) in cmd_class.help_options:
|
||||
if hasattr(opts, parser.get_attr_name(help_option)):
|
||||
help_option_found=1
|
||||
help_option_found = 1
|
||||
if callable(func):
|
||||
func()
|
||||
else:
|
||||
raise DistutilsClassError(
|
||||
"invalid help function %r for help option '%s': "
|
||||
"must be a callable object (function, etc.)"
|
||||
% (func, help_option))
|
||||
'must be a callable object (function, etc.)'
|
||||
% (func, help_option),
|
||||
)
|
||||
|
||||
if help_option_found:
|
||||
return
|
||||
|
|
@ -602,7 +668,7 @@ Common commands: (see '--help-commands' for more)
|
|||
# holding pen, the 'command_options' dictionary.
|
||||
opt_dict = self.get_option_dict(command)
|
||||
for (name, value) in vars(opts).items():
|
||||
opt_dict[name] = ("command line", value)
|
||||
opt_dict[name] = ('command line', value)
|
||||
|
||||
return args
|
||||
|
||||
|
|
@ -619,8 +685,10 @@ Common commands: (see '--help-commands' for more)
|
|||
value = [elm.strip() for elm in value.split(',')]
|
||||
setattr(self.metadata, attr, value)
|
||||
|
||||
def _show_help(self, parser, global_options=1, display_options=1,
|
||||
commands=[]):
|
||||
def _show_help(
|
||||
self, parser, global_options=1, display_options=1,
|
||||
commands=[],
|
||||
):
|
||||
"""Show help for the setup script command-line in the form of
|
||||
several lists of command-line options. 'parser' should be a
|
||||
FancyGetopt instance; do not expect it to be returned in the
|
||||
|
|
@ -643,14 +711,15 @@ Common commands: (see '--help-commands' for more)
|
|||
else:
|
||||
options = self.global_options
|
||||
parser.set_option_table(options)
|
||||
parser.print_help(self.common_usage + "\nGlobal options:")
|
||||
parser.print_help(self.common_usage + '\nGlobal options:')
|
||||
print('')
|
||||
|
||||
if display_options:
|
||||
parser.set_option_table(self.display_options)
|
||||
parser.print_help(
|
||||
"Information display options (just display " +
|
||||
"information, ignore any commands)")
|
||||
'Information display options (just display ' +
|
||||
'information, ignore any commands)',
|
||||
)
|
||||
print('')
|
||||
|
||||
for command in self.commands:
|
||||
|
|
@ -658,10 +727,14 @@ Common commands: (see '--help-commands' for more)
|
|||
klass = command
|
||||
else:
|
||||
klass = self.get_command_class(command)
|
||||
if (hasattr(klass, 'help_options') and
|
||||
isinstance(klass.help_options, list)):
|
||||
parser.set_option_table(klass.user_options +
|
||||
fix_help_options(klass.help_options))
|
||||
if (
|
||||
hasattr(klass, 'help_options') and
|
||||
isinstance(klass.help_options, list)
|
||||
):
|
||||
parser.set_option_table(
|
||||
klass.user_options +
|
||||
fix_help_options(klass.help_options),
|
||||
)
|
||||
else:
|
||||
parser.set_option_table(klass.user_options)
|
||||
parser.print_help("Options for '%s' command:" % klass.__name__)
|
||||
|
|
@ -697,11 +770,13 @@ Common commands: (see '--help-commands' for more)
|
|||
for (opt, val) in option_order:
|
||||
if val and is_display_option.get(opt):
|
||||
opt = translate_longopt(opt)
|
||||
value = getattr(self.metadata, "get_"+opt)()
|
||||
value = getattr(self.metadata, 'get_' + opt)()
|
||||
if opt in ['keywords', 'platforms']:
|
||||
print(','.join(value))
|
||||
elif opt in ('classifiers', 'provides', 'requires',
|
||||
'obsoletes'):
|
||||
elif opt in (
|
||||
'classifiers', 'provides', 'requires',
|
||||
'obsoletes',
|
||||
):
|
||||
print('\n'.join(value))
|
||||
else:
|
||||
print(value)
|
||||
|
|
@ -713,7 +788,7 @@ Common commands: (see '--help-commands' for more)
|
|||
"""Print a subset of the list of all commands -- used by
|
||||
'print_commands()'.
|
||||
"""
|
||||
print(header + ":")
|
||||
print(header + ':')
|
||||
|
||||
for cmd in commands:
|
||||
klass = self.cmdclass.get(cmd)
|
||||
|
|
@ -722,9 +797,9 @@ Common commands: (see '--help-commands' for more)
|
|||
try:
|
||||
description = klass.description
|
||||
except AttributeError:
|
||||
description = "(no description available)"
|
||||
description = '(no description available)'
|
||||
|
||||
print(" %-*s %s" % (max_length, cmd, description))
|
||||
print(' %-*s %s' % (max_length, cmd, description))
|
||||
|
||||
def print_commands(self):
|
||||
"""Print out a help message listing all available commands with a
|
||||
|
|
@ -750,14 +825,18 @@ Common commands: (see '--help-commands' for more)
|
|||
if len(cmd) > max_length:
|
||||
max_length = len(cmd)
|
||||
|
||||
self.print_command_list(std_commands,
|
||||
"Standard commands",
|
||||
max_length)
|
||||
self.print_command_list(
|
||||
std_commands,
|
||||
'Standard commands',
|
||||
max_length,
|
||||
)
|
||||
if extra_commands:
|
||||
print()
|
||||
self.print_command_list(extra_commands,
|
||||
"Extra commands",
|
||||
max_length)
|
||||
self.print_command_list(
|
||||
extra_commands,
|
||||
'Extra commands',
|
||||
max_length,
|
||||
)
|
||||
|
||||
def get_command_list(self):
|
||||
"""Get a list of (command, description) tuples.
|
||||
|
|
@ -787,7 +866,7 @@ Common commands: (see '--help-commands' for more)
|
|||
try:
|
||||
description = klass.description
|
||||
except AttributeError:
|
||||
description = "(no description available)"
|
||||
description = '(no description available)'
|
||||
rv.append((cmd, description))
|
||||
return rv
|
||||
|
||||
|
|
@ -800,8 +879,8 @@ Common commands: (see '--help-commands' for more)
|
|||
if pkgs is None:
|
||||
pkgs = ''
|
||||
pkgs = [pkg.strip() for pkg in pkgs.split(',') if pkg != '']
|
||||
if "distutils.command" not in pkgs:
|
||||
pkgs.insert(0, "distutils.command")
|
||||
if 'distutils.command' not in pkgs:
|
||||
pkgs.insert(0, 'distutils.command')
|
||||
self.command_packages = pkgs
|
||||
return pkgs
|
||||
|
||||
|
|
@ -822,7 +901,7 @@ Common commands: (see '--help-commands' for more)
|
|||
return klass
|
||||
|
||||
for pkgname in self.get_command_packages():
|
||||
module_name = "%s.%s" % (pkgname, command)
|
||||
module_name = '{}.{}'.format(pkgname, command)
|
||||
klass_name = command
|
||||
|
||||
try:
|
||||
|
|
@ -836,7 +915,8 @@ Common commands: (see '--help-commands' for more)
|
|||
except AttributeError:
|
||||
raise DistutilsModuleError(
|
||||
"invalid command '%s' (no class '%s' in module '%s')"
|
||||
% (command, klass_name, module_name))
|
||||
% (command, klass_name, module_name),
|
||||
)
|
||||
|
||||
self.cmdclass[command] = klass
|
||||
return klass
|
||||
|
|
@ -852,8 +932,10 @@ Common commands: (see '--help-commands' for more)
|
|||
cmd_obj = self.command_obj.get(command)
|
||||
if not cmd_obj and create:
|
||||
if DEBUG:
|
||||
self.announce("Distribution.get_command_obj(): "
|
||||
"creating '%s' command object" % command)
|
||||
self.announce(
|
||||
'Distribution.get_command_obj(): '
|
||||
"creating '%s' command object" % command,
|
||||
)
|
||||
|
||||
klass = self.get_command_class(command)
|
||||
cmd_obj = self.command_obj[command] = klass(self)
|
||||
|
|
@ -887,11 +969,17 @@ Common commands: (see '--help-commands' for more)
|
|||
self.announce(" setting options for '%s' command:" % command_name)
|
||||
for (option, (source, value)) in option_dict.items():
|
||||
if DEBUG:
|
||||
self.announce(" %s = %s (from %s)" % (option, value,
|
||||
source))
|
||||
self.announce(
|
||||
' {} = {} (from {})'.format(
|
||||
option, value,
|
||||
source,
|
||||
),
|
||||
)
|
||||
try:
|
||||
bool_opts = [translate_longopt(o)
|
||||
for o in command_obj.boolean_options]
|
||||
bool_opts = [
|
||||
translate_longopt(o)
|
||||
for o in command_obj.boolean_options
|
||||
]
|
||||
except AttributeError:
|
||||
bool_opts = []
|
||||
try:
|
||||
|
|
@ -910,7 +998,8 @@ Common commands: (see '--help-commands' for more)
|
|||
else:
|
||||
raise DistutilsOptionError(
|
||||
"error in %s: command '%s' has no such option '%s'"
|
||||
% (source, command_name, option))
|
||||
% (source, command_name, option),
|
||||
)
|
||||
except ValueError as msg:
|
||||
raise DistutilsOptionError(msg)
|
||||
|
||||
|
|
@ -980,7 +1069,7 @@ Common commands: (see '--help-commands' for more)
|
|||
if self.have_run.get(command):
|
||||
return
|
||||
|
||||
log.info("running %s", command)
|
||||
log.info('running %s', command)
|
||||
cmd_obj = self.get_command_obj(command)
|
||||
cmd_obj.ensure_finalized()
|
||||
cmd_obj.run()
|
||||
|
|
@ -1010,9 +1099,11 @@ Common commands: (see '--help-commands' for more)
|
|||
return self.data_files and len(self.data_files) > 0
|
||||
|
||||
def is_pure(self):
|
||||
return (self.has_pure_modules() and
|
||||
not self.has_ext_modules() and
|
||||
not self.has_c_libraries())
|
||||
return (
|
||||
self.has_pure_modules() and
|
||||
not self.has_ext_modules() and
|
||||
not self.has_c_libraries()
|
||||
)
|
||||
|
||||
# -- Metadata query methods ----------------------------------------
|
||||
|
||||
|
|
@ -1021,19 +1112,21 @@ Common commands: (see '--help-commands' for more)
|
|||
# to self.metadata.get_XXX. The actual code is in the
|
||||
# DistributionMetadata class, below.
|
||||
|
||||
|
||||
class DistributionMetadata:
|
||||
"""Dummy class to hold the distribution meta-data: name, version,
|
||||
author, and so forth.
|
||||
"""
|
||||
|
||||
_METHOD_BASENAMES = ("name", "version", "author", "author_email",
|
||||
"maintainer", "maintainer_email", "url",
|
||||
"license", "description", "long_description",
|
||||
"keywords", "platforms", "fullname", "contact",
|
||||
"contact_email", "classifiers", "download_url",
|
||||
# PEP 314
|
||||
"provides", "requires", "obsoletes",
|
||||
)
|
||||
_METHOD_BASENAMES = (
|
||||
'name', 'version', 'author', 'author_email',
|
||||
'maintainer', 'maintainer_email', 'url',
|
||||
'license', 'description', 'long_description',
|
||||
'keywords', 'platforms', 'fullname', 'contact',
|
||||
'contact_email', 'classifiers', 'download_url',
|
||||
# PEP 314
|
||||
'provides', 'requires', 'obsoletes',
|
||||
)
|
||||
|
||||
def __init__(self, path=None):
|
||||
if path is not None:
|
||||
|
|
@ -1113,16 +1206,20 @@ class DistributionMetadata:
|
|||
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:
|
||||
with open(
|
||||
os.path.join(base_dir, 'PKG-INFO'), 'w',
|
||||
encoding='UTF-8',
|
||||
) as pkg_info:
|
||||
self.write_pkg_file(pkg_info)
|
||||
|
||||
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):
|
||||
if (
|
||||
self.provides or self.requires or self.obsoletes or
|
||||
self.classifiers or self.download_url
|
||||
):
|
||||
version = '1.1'
|
||||
|
||||
file.write('Metadata-Version: %s\n' % version)
|
||||
|
|
@ -1153,49 +1250,49 @@ class DistributionMetadata:
|
|||
|
||||
def _write_list(self, file, name, values):
|
||||
for value in values:
|
||||
file.write('%s: %s\n' % (name, value))
|
||||
file.write('{}: {}\n'.format(name, value))
|
||||
|
||||
# -- Metadata query methods ----------------------------------------
|
||||
|
||||
def get_name(self):
|
||||
return self.name or "UNKNOWN"
|
||||
return self.name or 'UNKNOWN'
|
||||
|
||||
def get_version(self):
|
||||
return self.version or "0.0.0"
|
||||
return self.version or '0.0.0'
|
||||
|
||||
def get_fullname(self):
|
||||
return "%s-%s" % (self.get_name(), self.get_version())
|
||||
return '{}-{}'.format(self.get_name(), self.get_version())
|
||||
|
||||
def get_author(self):
|
||||
return self.author or "UNKNOWN"
|
||||
return self.author or 'UNKNOWN'
|
||||
|
||||
def get_author_email(self):
|
||||
return self.author_email or "UNKNOWN"
|
||||
return self.author_email or 'UNKNOWN'
|
||||
|
||||
def get_maintainer(self):
|
||||
return self.maintainer or "UNKNOWN"
|
||||
return self.maintainer or 'UNKNOWN'
|
||||
|
||||
def get_maintainer_email(self):
|
||||
return self.maintainer_email or "UNKNOWN"
|
||||
return self.maintainer_email or 'UNKNOWN'
|
||||
|
||||
def get_contact(self):
|
||||
return self.maintainer or self.author or "UNKNOWN"
|
||||
return self.maintainer or self.author or 'UNKNOWN'
|
||||
|
||||
def get_contact_email(self):
|
||||
return self.maintainer_email or self.author_email or "UNKNOWN"
|
||||
return self.maintainer_email or self.author_email or 'UNKNOWN'
|
||||
|
||||
def get_url(self):
|
||||
return self.url or "UNKNOWN"
|
||||
return self.url or 'UNKNOWN'
|
||||
|
||||
def get_license(self):
|
||||
return self.license or "UNKNOWN"
|
||||
return self.license or 'UNKNOWN'
|
||||
get_licence = get_license
|
||||
|
||||
def get_description(self):
|
||||
return self.description or "UNKNOWN"
|
||||
return self.description or 'UNKNOWN'
|
||||
|
||||
def get_long_description(self):
|
||||
return self.long_description or "UNKNOWN"
|
||||
return self.long_description or 'UNKNOWN'
|
||||
|
||||
def get_keywords(self):
|
||||
return self.keywords or []
|
||||
|
|
@ -1204,7 +1301,7 @@ class DistributionMetadata:
|
|||
self.keywords = _ensure_list(value, 'keywords')
|
||||
|
||||
def get_platforms(self):
|
||||
return self.platforms or ["UNKNOWN"]
|
||||
return self.platforms or ['UNKNOWN']
|
||||
|
||||
def set_platforms(self, value):
|
||||
self.platforms = _ensure_list(value, 'platforms')
|
||||
|
|
@ -1216,7 +1313,7 @@ class DistributionMetadata:
|
|||
self.classifiers = _ensure_list(value, 'classifiers')
|
||||
|
||||
def get_download_url(self):
|
||||
return self.download_url or "UNKNOWN"
|
||||
return self.download_url or 'UNKNOWN'
|
||||
|
||||
# PEP 314
|
||||
def get_requires(self):
|
||||
|
|
@ -1247,6 +1344,7 @@ class DistributionMetadata:
|
|||
distutils.versionpredicate.VersionPredicate(v)
|
||||
self.obsoletes = list(value)
|
||||
|
||||
|
||||
def fix_help_options(options):
|
||||
"""Convert a 4-tuple 'help_options' list as found in various command
|
||||
classes to the 3-tuple form required by FancyGetopt.
|
||||
|
|
|
|||
|
|
@ -7,16 +7,20 @@ usually raised for errors that are obviously the end-user's fault
|
|||
|
||||
This module is safe to use in "from ... import *" mode; it only exports
|
||||
symbols whose names start with "Distutils" and end with "Error"."""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class DistutilsError (Exception):
|
||||
"""The root of all Distutils evil."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsModuleError (DistutilsError):
|
||||
"""Unable to load an expected module, or to find an expected class
|
||||
within some module (in particular, command modules and classes)."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsClassError (DistutilsError):
|
||||
"""Some command class (or possibly distribution class, if anyone
|
||||
feels a need to subclass Distribution) is found not to be holding
|
||||
|
|
@ -24,21 +28,25 @@ class DistutilsClassError (DistutilsError):
|
|||
"command "interface."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsGetoptError (DistutilsError):
|
||||
"""The option table provided to 'fancy_getopt()' is bogus."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsArgError (DistutilsError):
|
||||
"""Raised by fancy_getopt in response to getopt.error -- ie. an
|
||||
error in the command line usage."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsFileError (DistutilsError):
|
||||
"""Any problems in the filesystem: expected file not found, etc.
|
||||
Typically this is for problems that we detect before OSError
|
||||
could be raised."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsOptionError (DistutilsError):
|
||||
"""Syntactic/semantic errors in command options, such as use of
|
||||
mutually conflicting options, or inconsistent options,
|
||||
|
|
@ -48,50 +56,63 @@ class DistutilsOptionError (DistutilsError):
|
|||
the setup script, we'll raise DistutilsSetupError instead."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsSetupError (DistutilsError):
|
||||
"""For errors that can be definitely blamed on the setup script,
|
||||
such as invalid keyword arguments to 'setup()'."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsPlatformError (DistutilsError):
|
||||
"""We don't know how to do something on the current platform (but
|
||||
we do know how to do it on some platform) -- eg. trying to compile
|
||||
C files on a platform not supported by a CCompiler subclass."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsExecError (DistutilsError):
|
||||
"""Any problems executing an external program (such as the C
|
||||
compiler, when compiling C files)."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsInternalError (DistutilsError):
|
||||
"""Internal inconsistencies or impossibilities (obviously, this
|
||||
should never be seen if the code is working!)."""
|
||||
pass
|
||||
|
||||
|
||||
class DistutilsTemplateError (DistutilsError):
|
||||
"""Syntax error in a file list template."""
|
||||
|
||||
|
||||
class DistutilsByteCompileError(DistutilsError):
|
||||
"""Byte compile error."""
|
||||
|
||||
# Exception classes used by the CCompiler implementation classes
|
||||
|
||||
|
||||
class CCompilerError (Exception):
|
||||
"""Some compile/link operation failed."""
|
||||
|
||||
|
||||
class PreprocessError (CCompilerError):
|
||||
"""Failure to preprocess one or more C/C++ files."""
|
||||
|
||||
|
||||
class CompileError (CCompilerError):
|
||||
"""Failure to compile one or more C/C++ source files."""
|
||||
|
||||
|
||||
class LibError (CCompilerError):
|
||||
"""Failure to create a static library from one or more C/C++ object
|
||||
files."""
|
||||
|
||||
|
||||
class LinkError (CCompilerError):
|
||||
"""Failure to link one or more C/C++ object files into an executable
|
||||
or shared library file."""
|
||||
|
||||
|
||||
class UnknownFileError (CCompilerError):
|
||||
"""Attempt to process an unknown file type."""
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
Provides the Extension class, used to describe C/C++ extension
|
||||
modules in setup scripts."""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import warnings
|
||||
|
|
@ -16,6 +17,7 @@ import warnings
|
|||
# import that large-ish module (indirectly, through distutils.core) in
|
||||
# order to do anything.
|
||||
|
||||
|
||||
class Extension:
|
||||
"""Just a collection of attributes that describes an extension
|
||||
module and everything needed to build it (hopefully in a portable
|
||||
|
|
@ -83,27 +85,30 @@ class Extension:
|
|||
|
||||
# When adding arguments to this constructor, be sure to update
|
||||
# setup_keywords in core.py.
|
||||
def __init__(self, name, sources,
|
||||
include_dirs=None,
|
||||
define_macros=None,
|
||||
undef_macros=None,
|
||||
library_dirs=None,
|
||||
libraries=None,
|
||||
runtime_library_dirs=None,
|
||||
extra_objects=None,
|
||||
extra_compile_args=None,
|
||||
extra_link_args=None,
|
||||
export_symbols=None,
|
||||
swig_opts = None,
|
||||
depends=None,
|
||||
language=None,
|
||||
optional=None,
|
||||
**kw # To catch unknown keywords
|
||||
):
|
||||
def __init__(
|
||||
self, name, sources,
|
||||
include_dirs=None,
|
||||
define_macros=None,
|
||||
undef_macros=None,
|
||||
library_dirs=None,
|
||||
libraries=None,
|
||||
runtime_library_dirs=None,
|
||||
extra_objects=None,
|
||||
extra_compile_args=None,
|
||||
extra_link_args=None,
|
||||
export_symbols=None,
|
||||
swig_opts=None,
|
||||
depends=None,
|
||||
language=None,
|
||||
optional=None,
|
||||
**kw, # To catch unknown keywords
|
||||
):
|
||||
if not isinstance(name, str):
|
||||
raise AssertionError("'name' must be a string")
|
||||
if not (isinstance(sources, list) and
|
||||
all(isinstance(v, str) for v in sources)):
|
||||
if not (
|
||||
isinstance(sources, list) and
|
||||
all(isinstance(v, str) for v in sources)
|
||||
):
|
||||
raise AssertionError("'sources' must be a list of strings")
|
||||
|
||||
self.name = name
|
||||
|
|
@ -127,21 +132,24 @@ class Extension:
|
|||
if len(kw) > 0:
|
||||
options = [repr(option) for option in kw]
|
||||
options = ', '.join(sorted(options))
|
||||
msg = "Unknown Extension options: %s" % options
|
||||
msg = 'Unknown Extension options: %s' % options
|
||||
warnings.warn(msg)
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s.%s(%r) at %#x>' % (
|
||||
return '<{}.{}({!r}) at {:#x}>'.format(
|
||||
self.__class__.__module__,
|
||||
self.__class__.__qualname__,
|
||||
self.name,
|
||||
id(self))
|
||||
id(self),
|
||||
)
|
||||
|
||||
|
||||
def read_setup_file(filename):
|
||||
"""Reads a Setup file and returns Extension instances."""
|
||||
from distutils.sysconfig import (parse_makefile, expand_makefile_vars,
|
||||
_variable_rx)
|
||||
from distutils.sysconfig import (
|
||||
parse_makefile, expand_makefile_vars,
|
||||
_variable_rx,
|
||||
)
|
||||
|
||||
from distutils.text_file import TextFile
|
||||
from distutils.util import split_quoted
|
||||
|
|
@ -151,9 +159,11 @@ def read_setup_file(filename):
|
|||
|
||||
# Second pass to gobble up the real content: lines of the form
|
||||
# <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...]
|
||||
file = TextFile(filename,
|
||||
strip_comments=1, skip_blanks=1, join_lines=1,
|
||||
lstrip_ws=1, rstrip_ws=1)
|
||||
file = TextFile(
|
||||
filename,
|
||||
strip_comments=1, skip_blanks=1, join_lines=1,
|
||||
lstrip_ws=1, rstrip_ws=1,
|
||||
)
|
||||
try:
|
||||
extensions = []
|
||||
|
||||
|
|
@ -164,7 +174,7 @@ def read_setup_file(filename):
|
|||
if _variable_rx.match(line): # VAR=VALUE, handled in first pass
|
||||
continue
|
||||
|
||||
if line[0] == line[-1] == "*":
|
||||
if line[0] == line[-1] == '*':
|
||||
file.warn("'%s' lines not handled yet" % line)
|
||||
continue
|
||||
|
||||
|
|
@ -188,43 +198,46 @@ def read_setup_file(filename):
|
|||
continue
|
||||
|
||||
suffix = os.path.splitext(word)[1]
|
||||
switch = word[0:2] ; value = word[2:]
|
||||
switch = word[0:2]
|
||||
value = word[2:]
|
||||
|
||||
if suffix in (".c", ".cc", ".cpp", ".cxx", ".c++", ".m", ".mm"):
|
||||
if suffix in ('.c', '.cc', '.cpp', '.cxx', '.c++', '.m', '.mm'):
|
||||
# hmm, should we do something about C vs. C++ sources?
|
||||
# or leave it up to the CCompiler implementation to
|
||||
# worry about?
|
||||
ext.sources.append(word)
|
||||
elif switch == "-I":
|
||||
elif switch == '-I':
|
||||
ext.include_dirs.append(value)
|
||||
elif switch == "-D":
|
||||
equals = value.find("=")
|
||||
elif switch == '-D':
|
||||
equals = value.find('=')
|
||||
if equals == -1: # bare "-DFOO" -- no value
|
||||
ext.define_macros.append((value, None))
|
||||
else: # "-DFOO=blah"
|
||||
ext.define_macros.append((value[0:equals],
|
||||
value[equals+2:]))
|
||||
elif switch == "-U":
|
||||
ext.define_macros.append((
|
||||
value[0:equals],
|
||||
value[equals + 2:],
|
||||
))
|
||||
elif switch == '-U':
|
||||
ext.undef_macros.append(value)
|
||||
elif switch == "-C": # only here 'cause makesetup has it!
|
||||
elif switch == '-C': # only here 'cause makesetup has it!
|
||||
ext.extra_compile_args.append(word)
|
||||
elif switch == "-l":
|
||||
elif switch == '-l':
|
||||
ext.libraries.append(value)
|
||||
elif switch == "-L":
|
||||
elif switch == '-L':
|
||||
ext.library_dirs.append(value)
|
||||
elif switch == "-R":
|
||||
elif switch == '-R':
|
||||
ext.runtime_library_dirs.append(value)
|
||||
elif word == "-rpath":
|
||||
elif word == '-rpath':
|
||||
append_next_word = ext.runtime_library_dirs
|
||||
elif word == "-Xlinker":
|
||||
elif word == '-Xlinker':
|
||||
append_next_word = ext.extra_link_args
|
||||
elif word == "-Xcompiler":
|
||||
elif word == '-Xcompiler':
|
||||
append_next_word = ext.extra_compile_args
|
||||
elif switch == "-u":
|
||||
elif switch == '-u':
|
||||
ext.extra_link_args.append(word)
|
||||
if not value:
|
||||
append_next_word = ext.extra_link_args
|
||||
elif suffix in (".a", ".so", ".sl", ".o", ".dylib"):
|
||||
elif suffix in ('.a', '.so', '.sl', '.o', '.dylib'):
|
||||
# NB. a really faithful emulation of makesetup would
|
||||
# append a .o file to extra_objects only if it
|
||||
# had a slash in it; otherwise, it would s/.o/.c/
|
||||
|
|
|
|||
|
|
@ -7,9 +7,13 @@ additional features:
|
|||
create a complete usage summary
|
||||
* options set attributes of a passed-in object
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys, string, re
|
||||
import getopt
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
|
||||
from distutils.errors import *
|
||||
|
||||
# Much like command_re in distutils.core, this is close to but not quite
|
||||
|
|
@ -20,12 +24,13 @@ longopt_pat = r'[a-zA-Z](?:[a-zA-Z0-9-]*)'
|
|||
longopt_re = re.compile(r'^%s$' % longopt_pat)
|
||||
|
||||
# For recognizing "negative alias" options, eg. "quiet=!verbose"
|
||||
neg_alias_re = re.compile("^(%s)=!(%s)$" % (longopt_pat, longopt_pat))
|
||||
neg_alias_re = re.compile('^({})=!({})$'.format(longopt_pat, longopt_pat))
|
||||
|
||||
# This is used to translate long options to legitimate Python identifiers
|
||||
# (for use as attributes of some object).
|
||||
longopt_xlate = str.maketrans('-', '_')
|
||||
|
||||
|
||||
class FancyGetopt:
|
||||
"""Wrapper around the standard 'getopt()' module that provides some
|
||||
handy extra functionality:
|
||||
|
|
@ -90,7 +95,8 @@ class FancyGetopt:
|
|||
def add_option(self, long_option, short_option=None, help_string=None):
|
||||
if long_option in self.option_index:
|
||||
raise DistutilsGetoptError(
|
||||
"option conflict: already an option '%s'" % long_option)
|
||||
"option conflict: already an option '%s'" % long_option,
|
||||
)
|
||||
else:
|
||||
option = (long_option, short_option, help_string)
|
||||
self.option_table.append(option)
|
||||
|
|
@ -111,15 +117,19 @@ class FancyGetopt:
|
|||
assert isinstance(aliases, dict)
|
||||
for (alias, opt) in aliases.items():
|
||||
if alias not in self.option_index:
|
||||
raise DistutilsGetoptError(("invalid %s '%s': "
|
||||
"option '%s' not defined") % (what, alias, alias))
|
||||
raise DistutilsGetoptError((
|
||||
"invalid %s '%s': "
|
||||
"option '%s' not defined"
|
||||
) % (what, alias, alias))
|
||||
if opt not in self.option_index:
|
||||
raise DistutilsGetoptError(("invalid %s '%s': "
|
||||
"aliased option '%s' not defined") % (what, alias, opt))
|
||||
raise DistutilsGetoptError((
|
||||
"invalid %s '%s': "
|
||||
"aliased option '%s' not defined"
|
||||
) % (what, alias, opt))
|
||||
|
||||
def set_aliases(self, alias):
|
||||
"""Set the aliases for this option parser."""
|
||||
self._check_alias_dict(alias, "alias")
|
||||
self._check_alias_dict(alias, 'alias')
|
||||
self.alias = alias
|
||||
|
||||
def set_negative_aliases(self, negative_alias):
|
||||
|
|
@ -127,7 +137,7 @@ class FancyGetopt:
|
|||
'negative_alias' should be a dictionary mapping option names to
|
||||
option names, both the key and value must already be defined
|
||||
in the option table."""
|
||||
self._check_alias_dict(negative_alias, "negative alias")
|
||||
self._check_alias_dict(negative_alias, 'negative alias')
|
||||
self.negative_alias = negative_alias
|
||||
|
||||
def _grok_option_table(self):
|
||||
|
|
@ -149,23 +159,32 @@ class FancyGetopt:
|
|||
else:
|
||||
# the option table is part of the code, so simply
|
||||
# assert that it is correct
|
||||
raise ValueError("invalid option tuple: %r" % (option,))
|
||||
raise ValueError('invalid option tuple: {!r}'.format(option))
|
||||
|
||||
# Type- and value-check the option names
|
||||
if not isinstance(long, str) or len(long) < 2:
|
||||
raise DistutilsGetoptError(("invalid long option '%s': "
|
||||
"must be a string of length >= 2") % long)
|
||||
raise DistutilsGetoptError(
|
||||
(
|
||||
"invalid long option '%s': "
|
||||
'must be a string of length >= 2'
|
||||
) % long,
|
||||
)
|
||||
|
||||
if (not ((short is None) or
|
||||
(isinstance(short, str) and len(short) == 1))):
|
||||
raise DistutilsGetoptError("invalid short option '%s': "
|
||||
"must a single character or None" % short)
|
||||
if (
|
||||
not ((short is None) or
|
||||
(isinstance(short, str) and len(short) == 1))
|
||||
):
|
||||
raise DistutilsGetoptError(
|
||||
"invalid short option '%s': "
|
||||
'must a single character or None' % short,
|
||||
)
|
||||
|
||||
self.repeat[long] = repeat
|
||||
self.long_opts.append(long)
|
||||
|
||||
if long[-1] == '=': # option takes an argument?
|
||||
if short: short = short + ':'
|
||||
if short:
|
||||
short = short + ':'
|
||||
long = long[0:-1]
|
||||
self.takes_arg[long] = 1
|
||||
else:
|
||||
|
|
@ -175,11 +194,12 @@ class FancyGetopt:
|
|||
if alias_to is not None:
|
||||
if self.takes_arg[alias_to]:
|
||||
raise DistutilsGetoptError(
|
||||
"invalid negative alias '%s': "
|
||||
"aliased option '%s' takes a value"
|
||||
% (long, alias_to))
|
||||
"invalid negative alias '%s': "
|
||||
"aliased option '%s' takes a value"
|
||||
% (long, alias_to),
|
||||
)
|
||||
|
||||
self.long_opts[-1] = long # XXX redundant?!
|
||||
self.long_opts[-1] = long # XXX redundant?!
|
||||
self.takes_arg[long] = 0
|
||||
|
||||
# If this is an alias option, make sure its "takes arg" flag is
|
||||
|
|
@ -188,10 +208,11 @@ class FancyGetopt:
|
|||
if alias_to is not None:
|
||||
if self.takes_arg[long] != self.takes_arg[alias_to]:
|
||||
raise DistutilsGetoptError(
|
||||
"invalid alias '%s': inconsistent with "
|
||||
"aliased option '%s' (one of them takes a value, "
|
||||
"the other doesn't"
|
||||
% (long, alias_to))
|
||||
"invalid alias '%s': inconsistent with "
|
||||
"aliased option '%s' (one of them takes a value, "
|
||||
"the other doesn't"
|
||||
% (long, alias_to),
|
||||
)
|
||||
|
||||
# Now enforce some bondage on the long option name, so we can
|
||||
# later translate it to an attribute name on some object. Have
|
||||
|
|
@ -199,8 +220,9 @@ class FancyGetopt:
|
|||
# '='.
|
||||
if not longopt_re.match(long):
|
||||
raise DistutilsGetoptError(
|
||||
"invalid long option name '%s' "
|
||||
"(must be letters, numbers, hyphens only" % long)
|
||||
"invalid long option name '%s' "
|
||||
'(must be letters, numbers, hyphens only' % long,
|
||||
)
|
||||
|
||||
self.attr_name[long] = self.get_attr_name(long)
|
||||
if short:
|
||||
|
|
@ -235,7 +257,7 @@ class FancyGetopt:
|
|||
raise DistutilsArgError(msg)
|
||||
|
||||
for opt, val in opts:
|
||||
if len(opt) == 2 and opt[0] == '-': # it's a short option
|
||||
if len(opt) == 2 and opt[0] == '-': # it's a short option
|
||||
opt = self.short2long[opt[1]]
|
||||
else:
|
||||
assert len(opt) > 2 and opt[:2] == '--'
|
||||
|
|
@ -339,19 +361,21 @@ class FancyGetopt:
|
|||
# Case 1: no short option at all (makes life easy)
|
||||
if short is None:
|
||||
if text:
|
||||
lines.append(" --%-*s %s" % (max_opt, long, text[0]))
|
||||
lines.append(' --%-*s %s' % (max_opt, long, text[0]))
|
||||
else:
|
||||
lines.append(" --%-*s " % (max_opt, long))
|
||||
lines.append(' --%-*s ' % (max_opt, long))
|
||||
|
||||
# Case 2: we have a short option, so we have to include it
|
||||
# just after the long option
|
||||
else:
|
||||
opt_names = "%s (-%s)" % (long, short)
|
||||
opt_names = '{} (-{})'.format(long, short)
|
||||
if text:
|
||||
lines.append(" --%-*s %s" %
|
||||
(max_opt, opt_names, text[0]))
|
||||
lines.append(
|
||||
' --%-*s %s' %
|
||||
(max_opt, opt_names, text[0]),
|
||||
)
|
||||
else:
|
||||
lines.append(" --%-*s" % opt_names)
|
||||
lines.append(' --%-*s' % opt_names)
|
||||
|
||||
for l in text[1:]:
|
||||
lines.append(big_indent + l)
|
||||
|
|
@ -361,7 +385,7 @@ class FancyGetopt:
|
|||
if file is None:
|
||||
file = sys.stdout
|
||||
for line in self.generate_help(header):
|
||||
file.write(line + "\n")
|
||||
file.write(line + '\n')
|
||||
|
||||
|
||||
def fancy_getopt(options, negative_opt, object, args):
|
||||
|
|
@ -370,7 +394,8 @@ def fancy_getopt(options, negative_opt, object, args):
|
|||
return parser.getopt(args, object)
|
||||
|
||||
|
||||
WS_TRANS = {ord(_wschar) : ' ' for _wschar in string.whitespace}
|
||||
WS_TRANS = {ord(_wschar): ' ' for _wschar in string.whitespace}
|
||||
|
||||
|
||||
def wrap_text(text, width):
|
||||
"""wrap_text(text : string, width : int) -> [string]
|
||||
|
|
@ -386,7 +411,7 @@ def wrap_text(text, width):
|
|||
text = text.expandtabs()
|
||||
text = text.translate(WS_TRANS)
|
||||
chunks = re.split(r'( +|-+)', text)
|
||||
chunks = [ch for ch in chunks if ch] # ' - ' results in empty strings
|
||||
chunks = [ch for ch in chunks if ch] # ' - ' results in empty strings
|
||||
lines = []
|
||||
|
||||
while chunks:
|
||||
|
|
@ -444,7 +469,7 @@ class OptionDummy:
|
|||
setattr(self, opt, None)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
text = """\
|
||||
Tra-la-la, supercalifragilisticexpialidocious.
|
||||
How *do* you spell that odd word, anyways?
|
||||
|
|
@ -452,6 +477,6 @@ How *do* you spell that odd word, anyways?
|
|||
say, "How should I know?"].)"""
|
||||
|
||||
for w in (10, 20, 30, 40):
|
||||
print("width: %d" % w)
|
||||
print("\n".join(wrap_text(text, w)))
|
||||
print('width: %d' % w)
|
||||
print('\n'.join(wrap_text(text, w)))
|
||||
print()
|
||||
|
|
|
|||
|
|
@ -2,18 +2,20 @@
|
|||
|
||||
Utility functions for operating on single files.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from distutils.errors import DistutilsFileError
|
||||
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsFileError
|
||||
|
||||
# for generating verbose output in 'copy_file()'
|
||||
_copy_action = { None: 'copying',
|
||||
'hard': 'hard linking',
|
||||
'sym': 'symbolically linking' }
|
||||
_copy_action = {None: 'copying',
|
||||
'hard': 'hard linking',
|
||||
'sym': 'symbolically linking', }
|
||||
|
||||
|
||||
def _copy_file_contents(src, dst, buffer_size=16*1024):
|
||||
def _copy_file_contents(src, dst, buffer_size=16 * 1024):
|
||||
"""Copy the file 'src' to 'dst'; both must be filenames. Any error
|
||||
opening either file, reading from 'src', or writing to 'dst', raises
|
||||
DistutilsFileError. Data is read/written in chunks of 'buffer_size'
|
||||
|
|
@ -28,27 +30,30 @@ def _copy_file_contents(src, dst, buffer_size=16*1024):
|
|||
try:
|
||||
fsrc = open(src, 'rb')
|
||||
except OSError as e:
|
||||
raise DistutilsFileError("could not open '%s': %s" % (src, e.strerror))
|
||||
raise DistutilsFileError("could not open '{}': {}".format(src, e.strerror))
|
||||
|
||||
if os.path.exists(dst):
|
||||
try:
|
||||
os.unlink(dst)
|
||||
except OSError as e:
|
||||
raise DistutilsFileError(
|
||||
"could not delete '%s': %s" % (dst, e.strerror))
|
||||
"could not delete '{}': {}".format(dst, e.strerror),
|
||||
)
|
||||
|
||||
try:
|
||||
fdst = open(dst, 'wb')
|
||||
except OSError as e:
|
||||
raise DistutilsFileError(
|
||||
"could not create '%s': %s" % (dst, e.strerror))
|
||||
"could not create '{}': {}".format(dst, e.strerror),
|
||||
)
|
||||
|
||||
while True:
|
||||
try:
|
||||
buf = fsrc.read(buffer_size)
|
||||
except OSError as e:
|
||||
raise DistutilsFileError(
|
||||
"could not read from '%s': %s" % (src, e.strerror))
|
||||
"could not read from '{}': {}".format(src, e.strerror),
|
||||
)
|
||||
|
||||
if not buf:
|
||||
break
|
||||
|
|
@ -57,15 +62,19 @@ def _copy_file_contents(src, dst, buffer_size=16*1024):
|
|||
fdst.write(buf)
|
||||
except OSError as e:
|
||||
raise DistutilsFileError(
|
||||
"could not write to '%s': %s" % (dst, e.strerror))
|
||||
"could not write to '{}': {}".format(dst, e.strerror),
|
||||
)
|
||||
finally:
|
||||
if fdst:
|
||||
fdst.close()
|
||||
if fsrc:
|
||||
fsrc.close()
|
||||
|
||||
def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0,
|
||||
link=None, verbose=1, dry_run=0):
|
||||
|
||||
def copy_file(
|
||||
src, dst, preserve_mode=1, preserve_times=1, update=0,
|
||||
link=None, verbose=1, dry_run=0,
|
||||
):
|
||||
"""Copy a file 'src' to 'dst'. If 'dst' is a directory, then 'src' is
|
||||
copied there with the same name; otherwise, it must be a filename. (If
|
||||
the file exists, it will be ruthlessly clobbered.) If 'preserve_mode'
|
||||
|
|
@ -102,7 +111,8 @@ def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0,
|
|||
|
||||
if not os.path.isfile(src):
|
||||
raise DistutilsFileError(
|
||||
"can't copy '%s': doesn't exist or not a regular file" % src)
|
||||
"can't copy '%s': doesn't exist or not a regular file" % src,
|
||||
)
|
||||
|
||||
if os.path.isdir(dst):
|
||||
dir = dst
|
||||
|
|
@ -112,7 +122,7 @@ def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0,
|
|||
|
||||
if update and not newer(src, dst):
|
||||
if verbose >= 1:
|
||||
log.debug("not copying %s (output up-to-date)", src)
|
||||
log.debug('not copying %s (output up-to-date)', src)
|
||||
return (dst, 0)
|
||||
|
||||
try:
|
||||
|
|
@ -122,9 +132,9 @@ def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0,
|
|||
|
||||
if verbose >= 1:
|
||||
if os.path.basename(dst) == os.path.basename(src):
|
||||
log.info("%s %s -> %s", action, src, dir)
|
||||
log.info('%s %s -> %s', action, src, dir)
|
||||
else:
|
||||
log.info("%s %s -> %s", action, src, dst)
|
||||
log.info('%s %s -> %s', action, src, dst)
|
||||
|
||||
if dry_run:
|
||||
return (dst, 1)
|
||||
|
|
@ -163,10 +173,11 @@ def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0,
|
|||
|
||||
|
||||
# XXX I suspect this is Unix-specific -- need porting help!
|
||||
def move_file (src, dst,
|
||||
verbose=1,
|
||||
dry_run=0):
|
||||
|
||||
def move_file(
|
||||
src, dst,
|
||||
verbose=1,
|
||||
dry_run=0,
|
||||
):
|
||||
"""Move a file 'src' to 'dst'. If 'dst' is a directory, the file will
|
||||
be moved into it with the same name; otherwise, 'src' is just renamed
|
||||
to 'dst'. Return the new full name of the file.
|
||||
|
|
@ -178,7 +189,7 @@ def move_file (src, dst,
|
|||
import errno
|
||||
|
||||
if verbose >= 1:
|
||||
log.info("moving %s -> %s", src, dst)
|
||||
log.info('moving %s -> %s', src, dst)
|
||||
|
||||
if dry_run:
|
||||
return dst
|
||||
|
|
@ -190,13 +201,15 @@ def move_file (src, dst,
|
|||
dst = os.path.join(dst, basename(src))
|
||||
elif exists(dst):
|
||||
raise DistutilsFileError(
|
||||
"can't move '%s': destination '%s' already exists" %
|
||||
(src, dst))
|
||||
"can't move '%s': destination '%s' already exists" %
|
||||
(src, dst),
|
||||
)
|
||||
|
||||
if not isdir(dirname(dst)):
|
||||
raise DistutilsFileError(
|
||||
"can't move '%s': destination '%s' not a valid path" %
|
||||
(src, dst))
|
||||
"can't move '%s': destination '%s' not a valid path" %
|
||||
(src, dst),
|
||||
)
|
||||
|
||||
copy_it = False
|
||||
try:
|
||||
|
|
@ -207,7 +220,8 @@ def move_file (src, dst,
|
|||
copy_it = True
|
||||
else:
|
||||
raise DistutilsFileError(
|
||||
"couldn't move '%s' to '%s': %s" % (src, dst, msg))
|
||||
"couldn't move '{}' to '{}': {}".format(src, dst, msg),
|
||||
)
|
||||
|
||||
if copy_it:
|
||||
copy_file(src, dst, verbose=verbose)
|
||||
|
|
@ -220,19 +234,20 @@ def move_file (src, dst,
|
|||
except OSError:
|
||||
pass
|
||||
raise DistutilsFileError(
|
||||
"couldn't move '%s' to '%s' by copy/delete: "
|
||||
"delete '%s' failed: %s"
|
||||
% (src, dst, src, msg))
|
||||
"couldn't move '%s' to '%s' by copy/delete: "
|
||||
"delete '%s' failed: %s"
|
||||
% (src, dst, src, msg),
|
||||
)
|
||||
return dst
|
||||
|
||||
|
||||
def write_file (filename, contents):
|
||||
def write_file(filename, contents):
|
||||
"""Create a file with the specified name and write 'contents' (a
|
||||
sequence of strings without line terminators) to it.
|
||||
"""
|
||||
f = open(filename, "w")
|
||||
f = open(filename, 'w')
|
||||
try:
|
||||
for line in contents:
|
||||
f.write(line + "\n")
|
||||
f.write(line + '\n')
|
||||
finally:
|
||||
f.close()
|
||||
|
|
|
|||
|
|
@ -3,15 +3,17 @@
|
|||
Provides the FileList class, used for poking about the filesystem
|
||||
and building lists of files.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import fnmatch
|
||||
import functools
|
||||
import os
|
||||
import re
|
||||
|
||||
from distutils.util import convert_path
|
||||
from distutils.errors import DistutilsTemplateError, DistutilsInternalError
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsInternalError
|
||||
from distutils.errors import DistutilsTemplateError
|
||||
from distutils.util import convert_path
|
||||
|
||||
|
||||
class FileList:
|
||||
|
|
@ -80,22 +82,27 @@ class FileList:
|
|||
|
||||
patterns = dir = dir_pattern = None
|
||||
|
||||
if action in ('include', 'exclude',
|
||||
'global-include', 'global-exclude'):
|
||||
if action in (
|
||||
'include', 'exclude',
|
||||
'global-include', 'global-exclude',
|
||||
):
|
||||
if len(words) < 2:
|
||||
raise DistutilsTemplateError(
|
||||
"'%s' expects <pattern1> <pattern2> ..." % action)
|
||||
"'%s' expects <pattern1> <pattern2> ..." % action,
|
||||
)
|
||||
patterns = [convert_path(w) for w in words[1:]]
|
||||
elif action in ('recursive-include', 'recursive-exclude'):
|
||||
if len(words) < 3:
|
||||
raise DistutilsTemplateError(
|
||||
"'%s' expects <dir> <pattern1> <pattern2> ..." % action)
|
||||
"'%s' expects <dir> <pattern1> <pattern2> ..." % action,
|
||||
)
|
||||
dir = convert_path(words[1])
|
||||
patterns = [convert_path(w) for w in words[2:]]
|
||||
elif action in ('graft', 'prune'):
|
||||
if len(words) != 2:
|
||||
raise DistutilsTemplateError(
|
||||
"'%s' expects a single <dir_pattern>" % action)
|
||||
"'%s' expects a single <dir_pattern>" % action,
|
||||
)
|
||||
dir_pattern = convert_path(words[1])
|
||||
else:
|
||||
raise DistutilsTemplateError("unknown action '%s'" % action)
|
||||
|
|
@ -114,37 +121,53 @@ class FileList:
|
|||
# right number of words on the line for that action -- so we
|
||||
# can proceed with minimal error-checking.
|
||||
if action == 'include':
|
||||
self.debug_print("include " + ' '.join(patterns))
|
||||
self.debug_print('include ' + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.include_pattern(pattern, anchor=1):
|
||||
log.warn("warning: no files found matching '%s'",
|
||||
pattern)
|
||||
log.warn(
|
||||
"warning: no files found matching '%s'",
|
||||
pattern,
|
||||
)
|
||||
|
||||
elif action == 'exclude':
|
||||
self.debug_print("exclude " + ' '.join(patterns))
|
||||
self.debug_print('exclude ' + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.exclude_pattern(pattern, anchor=1):
|
||||
log.warn(("warning: no previously-included files "
|
||||
"found matching '%s'"), pattern)
|
||||
log.warn(
|
||||
(
|
||||
'warning: no previously-included files '
|
||||
"found matching '%s'"
|
||||
), pattern,
|
||||
)
|
||||
|
||||
elif action == 'global-include':
|
||||
self.debug_print("global-include " + ' '.join(patterns))
|
||||
self.debug_print('global-include ' + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.include_pattern(pattern, anchor=0):
|
||||
log.warn(("warning: no files found matching '%s' "
|
||||
"anywhere in distribution"), pattern)
|
||||
log.warn(
|
||||
(
|
||||
"warning: no files found matching '%s' "
|
||||
'anywhere in distribution'
|
||||
), pattern,
|
||||
)
|
||||
|
||||
elif action == 'global-exclude':
|
||||
self.debug_print("global-exclude " + ' '.join(patterns))
|
||||
self.debug_print('global-exclude ' + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.exclude_pattern(pattern, anchor=0):
|
||||
log.warn(("warning: no previously-included files matching "
|
||||
"'%s' found anywhere in distribution"),
|
||||
pattern)
|
||||
log.warn(
|
||||
(
|
||||
'warning: no previously-included files matching '
|
||||
"'%s' found anywhere in distribution"
|
||||
),
|
||||
pattern,
|
||||
)
|
||||
|
||||
elif action == 'recursive-include':
|
||||
self.debug_print("recursive-include %s %s" %
|
||||
(dir, ' '.join(patterns)))
|
||||
self.debug_print(
|
||||
'recursive-include %s %s' %
|
||||
(dir, ' '.join(patterns)),
|
||||
)
|
||||
for pattern in patterns:
|
||||
if not self.include_pattern(pattern, prefix=dir):
|
||||
msg = (
|
||||
|
|
@ -154,28 +177,41 @@ class FileList:
|
|||
log.warn(msg, pattern, dir)
|
||||
|
||||
elif action == 'recursive-exclude':
|
||||
self.debug_print("recursive-exclude %s %s" %
|
||||
(dir, ' '.join(patterns)))
|
||||
self.debug_print(
|
||||
'recursive-exclude %s %s' %
|
||||
(dir, ' '.join(patterns)),
|
||||
)
|
||||
for pattern in patterns:
|
||||
if not self.exclude_pattern(pattern, prefix=dir):
|
||||
log.warn(("warning: no previously-included files matching "
|
||||
"'%s' found under directory '%s'"),
|
||||
pattern, dir)
|
||||
log.warn(
|
||||
(
|
||||
'warning: no previously-included files matching '
|
||||
"'%s' found under directory '%s'"
|
||||
),
|
||||
pattern, dir,
|
||||
)
|
||||
|
||||
elif action == 'graft':
|
||||
self.debug_print("graft " + dir_pattern)
|
||||
self.debug_print('graft ' + dir_pattern)
|
||||
if not self.include_pattern(None, prefix=dir_pattern):
|
||||
log.warn("warning: no directories found matching '%s'",
|
||||
dir_pattern)
|
||||
log.warn(
|
||||
"warning: no directories found matching '%s'",
|
||||
dir_pattern,
|
||||
)
|
||||
|
||||
elif action == 'prune':
|
||||
self.debug_print("prune " + dir_pattern)
|
||||
self.debug_print('prune ' + dir_pattern)
|
||||
if not self.exclude_pattern(None, prefix=dir_pattern):
|
||||
log.warn(("no previously-included directories found "
|
||||
"matching '%s'"), dir_pattern)
|
||||
log.warn(
|
||||
(
|
||||
'no previously-included directories found '
|
||||
"matching '%s'"
|
||||
), dir_pattern,
|
||||
)
|
||||
else:
|
||||
raise DistutilsInternalError(
|
||||
"this cannot happen: invalid action '%s'" % action)
|
||||
"this cannot happen: invalid action '%s'" % action,
|
||||
)
|
||||
|
||||
# Filtering/selection methods
|
||||
|
||||
|
|
@ -207,8 +243,10 @@ class FileList:
|
|||
# XXX docstring lying about what the special chars are?
|
||||
files_found = False
|
||||
pattern_re = translate_pattern(pattern, anchor, prefix, is_regex)
|
||||
self.debug_print("include_pattern: applying regex r'%s'" %
|
||||
pattern_re.pattern)
|
||||
self.debug_print(
|
||||
"include_pattern: applying regex r'%s'" %
|
||||
pattern_re.pattern,
|
||||
)
|
||||
|
||||
# delayed loading of allfiles list
|
||||
if self.allfiles is None:
|
||||
|
|
@ -216,13 +254,14 @@ class FileList:
|
|||
|
||||
for name in self.allfiles:
|
||||
if pattern_re.search(name):
|
||||
self.debug_print(" adding " + name)
|
||||
self.debug_print(' adding ' + name)
|
||||
self.files.append(name)
|
||||
files_found = True
|
||||
return files_found
|
||||
|
||||
def exclude_pattern(
|
||||
self, pattern, anchor=1, prefix=None, is_regex=0):
|
||||
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.
|
||||
|
|
@ -231,11 +270,13 @@ class FileList:
|
|||
"""
|
||||
files_found = False
|
||||
pattern_re = translate_pattern(pattern, anchor, prefix, is_regex)
|
||||
self.debug_print("exclude_pattern: applying regex r'%s'" %
|
||||
pattern_re.pattern)
|
||||
for i in range(len(self.files)-1, -1, -1):
|
||||
self.debug_print(
|
||||
"exclude_pattern: applying regex r'%s'" %
|
||||
pattern_re.pattern,
|
||||
)
|
||||
for i in range(len(self.files) - 1, -1, -1):
|
||||
if pattern_re.search(self.files[i]):
|
||||
self.debug_print(" removing " + self.files[i])
|
||||
self.debug_print(' removing ' + self.files[i])
|
||||
del self.files[i]
|
||||
files_found = True
|
||||
return files_found
|
||||
|
|
@ -262,6 +303,7 @@ class _UniqueDirs(set):
|
|||
avoiding infinite recursion.
|
||||
Ref https://bugs.python.org/issue44497.
|
||||
"""
|
||||
|
||||
def __call__(self, walk_item):
|
||||
"""
|
||||
Given an item from an os.walk result, determine
|
||||
|
|
@ -346,10 +388,11 @@ 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'{}\A{}{}.*{}{}'.format(
|
||||
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):])
|
||||
pattern_re = r'{}\A{}'.format(start, pattern_re[len(start):])
|
||||
|
||||
return re.compile(pattern_re)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""A simple log mechanism styled after PEP 282."""
|
||||
|
||||
# The class here is styled after PEP 282 so that it could later be
|
||||
# replaced with a standard Python logging implementation.
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
|
||||
DEBUG = 1
|
||||
INFO = 2
|
||||
|
|
@ -9,7 +10,6 @@ WARN = 3
|
|||
ERROR = 4
|
||||
FATAL = 5
|
||||
|
||||
import sys
|
||||
|
||||
class Log:
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ class Log:
|
|||
except UnicodeEncodeError:
|
||||
# emulate backslashreplace error handler
|
||||
encoding = stream.encoding
|
||||
msg = msg.encode(encoding, "backslashreplace").decode(encoding)
|
||||
msg = msg.encode(encoding, 'backslashreplace').decode(encoding)
|
||||
stream.write('%s\n' % msg)
|
||||
stream.flush()
|
||||
|
||||
|
|
@ -54,6 +54,7 @@ class Log:
|
|||
def fatal(self, msg, *args):
|
||||
self._log(FATAL, msg, args)
|
||||
|
||||
|
||||
_global_log = Log()
|
||||
log = _global_log.log
|
||||
debug = _global_log.debug
|
||||
|
|
@ -62,12 +63,14 @@ warn = _global_log.warn
|
|||
error = _global_log.error
|
||||
fatal = _global_log.fatal
|
||||
|
||||
|
||||
def set_threshold(level):
|
||||
# return the old threshold for use from tests
|
||||
old = _global_log.threshold
|
||||
_global_log.threshold = level
|
||||
return old
|
||||
|
||||
|
||||
def set_verbosity(v):
|
||||
if v <= 0:
|
||||
set_threshold(WARN)
|
||||
|
|
|
|||
|
|
@ -6,56 +6,62 @@ for the Microsoft Visual Studio 2008.
|
|||
The module is compatible with VS 2005 and VS 2008. You can find legacy support
|
||||
for older versions of VS in distutils.msvccompiler.
|
||||
"""
|
||||
|
||||
# Written by Perry Stoll
|
||||
# hacked by Robin Becker and Thomas Heller to do a better job of
|
||||
# finding DevStudio (through the registry)
|
||||
# ported to VS2005 and VS 2008 by Christian Heimes
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
|
||||
CompileError, LibError, LinkError
|
||||
from distutils.ccompiler import CCompiler, gen_lib_options
|
||||
from distutils import log
|
||||
from distutils.util import get_platform
|
||||
|
||||
import winreg
|
||||
|
||||
from distutils import log
|
||||
from distutils.ccompiler import CCompiler
|
||||
from distutils.ccompiler import gen_lib_options
|
||||
from distutils.errors import CompileError
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
from distutils.errors import LibError
|
||||
from distutils.errors import LinkError
|
||||
from distutils.util import get_platform
|
||||
|
||||
RegOpenKeyEx = winreg.OpenKeyEx
|
||||
RegEnumKey = winreg.EnumKey
|
||||
RegEnumValue = winreg.EnumValue
|
||||
RegError = winreg.error
|
||||
|
||||
HKEYS = (winreg.HKEY_USERS,
|
||||
winreg.HKEY_CURRENT_USER,
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
winreg.HKEY_CLASSES_ROOT)
|
||||
HKEYS = (
|
||||
winreg.HKEY_USERS,
|
||||
winreg.HKEY_CURRENT_USER,
|
||||
winreg.HKEY_LOCAL_MACHINE,
|
||||
winreg.HKEY_CLASSES_ROOT,
|
||||
)
|
||||
|
||||
NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)
|
||||
if NATIVE_WIN64:
|
||||
# Visual C++ is a 32-bit application, so we need to look in
|
||||
# the corresponding registry branch, if we're running a
|
||||
# 64-bit Python on Win64
|
||||
VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
|
||||
WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"
|
||||
NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework"
|
||||
VS_BASE = r'Software\Wow6432Node\Microsoft\VisualStudio\%0.1f'
|
||||
WINSDK_BASE = r'Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows'
|
||||
NET_BASE = r'Software\Wow6432Node\Microsoft\.NETFramework'
|
||||
else:
|
||||
VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
|
||||
WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
|
||||
NET_BASE = r"Software\Microsoft\.NETFramework"
|
||||
VS_BASE = r'Software\Microsoft\VisualStudio\%0.1f'
|
||||
WINSDK_BASE = r'Software\Microsoft\Microsoft SDKs\Windows'
|
||||
NET_BASE = r'Software\Microsoft\.NETFramework'
|
||||
|
||||
# A map keyed by get_platform() return values to values accepted by
|
||||
# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
|
||||
# the param to cross-compile on x86 targeting amd64.)
|
||||
PLAT_TO_VCVARS = {
|
||||
'win32' : 'x86',
|
||||
'win-amd64' : 'amd64',
|
||||
'win32': 'x86',
|
||||
'win-amd64': 'amd64',
|
||||
}
|
||||
|
||||
|
||||
class Reg:
|
||||
"""Helper class to read values from the registry
|
||||
"""
|
||||
|
|
@ -109,15 +115,16 @@ class Reg:
|
|||
read_values = classmethod(read_values)
|
||||
|
||||
def convert_mbcs(s):
|
||||
dec = getattr(s, "decode", None)
|
||||
dec = getattr(s, 'decode', None)
|
||||
if dec is not None:
|
||||
try:
|
||||
s = dec("mbcs")
|
||||
s = dec('mbcs')
|
||||
except UnicodeError:
|
||||
pass
|
||||
return s
|
||||
convert_mbcs = staticmethod(convert_mbcs)
|
||||
|
||||
|
||||
class MacroExpander:
|
||||
|
||||
def __init__(self, version):
|
||||
|
|
@ -126,56 +133,60 @@ class MacroExpander:
|
|||
self.load_macros(version)
|
||||
|
||||
def set_macro(self, macro, path, key):
|
||||
self.macros["$(%s)" % macro] = Reg.get_value(path, key)
|
||||
self.macros['$(%s)' % macro] = Reg.get_value(path, key)
|
||||
|
||||
def load_macros(self, version):
|
||||
self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
|
||||
self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
|
||||
self.set_macro("FrameworkDir", NET_BASE, "installroot")
|
||||
self.set_macro('VCInstallDir', self.vsbase + r'\Setup\VC', 'productdir')
|
||||
self.set_macro('VSInstallDir', self.vsbase + r'\Setup\VS', 'productdir')
|
||||
self.set_macro('FrameworkDir', NET_BASE, 'installroot')
|
||||
try:
|
||||
if version >= 8.0:
|
||||
self.set_macro("FrameworkSDKDir", NET_BASE,
|
||||
"sdkinstallrootv2.0")
|
||||
self.set_macro(
|
||||
'FrameworkSDKDir', NET_BASE,
|
||||
'sdkinstallrootv2.0',
|
||||
)
|
||||
else:
|
||||
raise KeyError("sdkinstallrootv2.0")
|
||||
raise KeyError('sdkinstallrootv2.0')
|
||||
except KeyError:
|
||||
raise DistutilsPlatformError(
|
||||
"""Python was built with Visual Studio 2008;
|
||||
"""Python was built with Visual Studio 2008;
|
||||
extensions must be built with a compiler than can generate compatible binaries.
|
||||
Visual Studio 2008 was not found on this system. If you have Cygwin installed,
|
||||
you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
|
||||
you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""",
|
||||
)
|
||||
|
||||
if version >= 9.0:
|
||||
self.set_macro("FrameworkVersion", self.vsbase, "clr version")
|
||||
self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
|
||||
self.set_macro('FrameworkVersion', self.vsbase, 'clr version')
|
||||
self.set_macro('WindowsSdkDir', WINSDK_BASE, 'currentinstallfolder')
|
||||
else:
|
||||
p = r"Software\Microsoft\NET Framework Setup\Product"
|
||||
p = r'Software\Microsoft\NET Framework Setup\Product'
|
||||
for base in HKEYS:
|
||||
try:
|
||||
h = RegOpenKeyEx(base, p)
|
||||
except RegError:
|
||||
continue
|
||||
key = RegEnumKey(h, 0)
|
||||
d = Reg.get_value(base, r"%s\%s" % (p, key))
|
||||
self.macros["$(FrameworkVersion)"] = d["version"]
|
||||
d = Reg.get_value(base, r'{}\{}'.format(p, key))
|
||||
self.macros['$(FrameworkVersion)'] = d['version']
|
||||
|
||||
def sub(self, s):
|
||||
for k, v in self.macros.items():
|
||||
s = s.replace(k, v)
|
||||
return s
|
||||
|
||||
|
||||
def get_build_version():
|
||||
"""Return the version of MSVC that was used to build Python.
|
||||
|
||||
For Python 2.3 and up, the version number is included in
|
||||
sys.version. For earlier versions, assume the compiler is MSVC 6.
|
||||
"""
|
||||
prefix = "MSC v."
|
||||
prefix = 'MSC v.'
|
||||
i = sys.version.find(prefix)
|
||||
if i == -1:
|
||||
return 6
|
||||
i = i + len(prefix)
|
||||
s, rest = sys.version[i:].split(" ", 1)
|
||||
s, rest = sys.version[i:].split(' ', 1)
|
||||
majorVersion = int(s[:-2]) - 6
|
||||
if majorVersion >= 13:
|
||||
# v13 was skipped and should be v14
|
||||
|
|
@ -189,6 +200,7 @@ def get_build_version():
|
|||
# else we don't know what version of the compiler this is
|
||||
return None
|
||||
|
||||
|
||||
def normalize_and_reduce_paths(paths):
|
||||
"""Return a list of normalized paths with duplicates removed.
|
||||
|
||||
|
|
@ -203,6 +215,7 @@ def normalize_and_reduce_paths(paths):
|
|||
reduced_paths.append(np)
|
||||
return reduced_paths
|
||||
|
||||
|
||||
def removeDuplicates(variable):
|
||||
"""Remove duplicate values of an environment variable.
|
||||
"""
|
||||
|
|
@ -214,6 +227,7 @@ def removeDuplicates(variable):
|
|||
newVariable = os.pathsep.join(newList)
|
||||
return newVariable
|
||||
|
||||
|
||||
def find_vcvarsall(version):
|
||||
"""Find the vcvarsall.bat file
|
||||
|
||||
|
|
@ -222,53 +236,58 @@ def find_vcvarsall(version):
|
|||
"""
|
||||
vsbase = VS_BASE % version
|
||||
try:
|
||||
productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
|
||||
"productdir")
|
||||
productdir = Reg.get_value(
|
||||
r'%s\Setup\VC' % vsbase,
|
||||
'productdir',
|
||||
)
|
||||
except KeyError:
|
||||
log.debug("Unable to find productdir in registry")
|
||||
log.debug('Unable to find productdir in registry')
|
||||
productdir = None
|
||||
|
||||
if not productdir or not os.path.isdir(productdir):
|
||||
toolskey = "VS%0.f0COMNTOOLS" % version
|
||||
toolskey = 'VS%0.f0COMNTOOLS' % version
|
||||
toolsdir = os.environ.get(toolskey, None)
|
||||
|
||||
if toolsdir and os.path.isdir(toolsdir):
|
||||
productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
|
||||
productdir = os.path.join(toolsdir, os.pardir, os.pardir, 'VC')
|
||||
productdir = os.path.abspath(productdir)
|
||||
if not os.path.isdir(productdir):
|
||||
log.debug("%s is not a valid directory" % productdir)
|
||||
log.debug('%s is not a valid directory' % productdir)
|
||||
return None
|
||||
else:
|
||||
log.debug("Env var %s is not set or invalid" % toolskey)
|
||||
log.debug('Env var %s is not set or invalid' % toolskey)
|
||||
if not productdir:
|
||||
log.debug("No productdir found")
|
||||
log.debug('No productdir found')
|
||||
return None
|
||||
vcvarsall = os.path.join(productdir, "vcvarsall.bat")
|
||||
vcvarsall = os.path.join(productdir, 'vcvarsall.bat')
|
||||
if os.path.isfile(vcvarsall):
|
||||
return vcvarsall
|
||||
log.debug("Unable to find vcvarsall.bat")
|
||||
log.debug('Unable to find vcvarsall.bat')
|
||||
return None
|
||||
|
||||
def query_vcvarsall(version, arch="x86"):
|
||||
|
||||
def query_vcvarsall(version, arch='x86'):
|
||||
"""Launch vcvarsall.bat and read the settings from its environment
|
||||
"""
|
||||
vcvarsall = find_vcvarsall(version)
|
||||
interesting = {"include", "lib", "libpath", "path"}
|
||||
interesting = {'include', 'lib', 'libpath', 'path'}
|
||||
result = {}
|
||||
|
||||
if vcvarsall is None:
|
||||
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
|
||||
raise DistutilsPlatformError('Unable to find vcvarsall.bat')
|
||||
log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
|
||||
popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
popen = subprocess.Popen(
|
||||
'"{}" {} & set'.format(vcvarsall, arch),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
try:
|
||||
stdout, stderr = popen.communicate()
|
||||
if popen.wait() != 0:
|
||||
raise DistutilsPlatformError(stderr.decode("mbcs"))
|
||||
raise DistutilsPlatformError(stderr.decode('mbcs'))
|
||||
|
||||
stdout = stdout.decode("mbcs")
|
||||
for line in stdout.split("\n"):
|
||||
stdout = stdout.decode('mbcs')
|
||||
for line in stdout.split('\n'):
|
||||
line = Reg.convert_mbcs(line)
|
||||
if '=' not in line:
|
||||
continue
|
||||
|
|
@ -289,13 +308,15 @@ def query_vcvarsall(version, arch="x86"):
|
|||
|
||||
return result
|
||||
|
||||
|
||||
# More globals
|
||||
VERSION = get_build_version()
|
||||
if VERSION < 8.0:
|
||||
raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
|
||||
raise DistutilsPlatformError('VC %0.1f is not supported by this module' % VERSION)
|
||||
# MACROS = MacroExpander(VERSION)
|
||||
|
||||
class MSVCCompiler(CCompiler) :
|
||||
|
||||
class MSVCCompiler(CCompiler):
|
||||
"""Concrete class that implements an interface to Microsoft Visual C++,
|
||||
as defined by the CCompiler abstract class."""
|
||||
|
||||
|
|
@ -316,8 +337,10 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
# Needed for the filename generation methods provided by the
|
||||
# base class, CCompiler.
|
||||
src_extensions = (_c_extensions + _cpp_extensions +
|
||||
_rc_extensions + _mc_extensions)
|
||||
src_extensions = (
|
||||
_c_extensions + _cpp_extensions +
|
||||
_rc_extensions + _mc_extensions
|
||||
)
|
||||
res_extension = '.res'
|
||||
obj_extension = '.obj'
|
||||
static_lib_extension = '.lib'
|
||||
|
|
@ -326,14 +349,14 @@ class MSVCCompiler(CCompiler) :
|
|||
exe_extension = '.exe'
|
||||
|
||||
def __init__(self, verbose=0, dry_run=0, force=0):
|
||||
CCompiler.__init__ (self, verbose, dry_run, force)
|
||||
CCompiler.__init__(self, verbose, dry_run, force)
|
||||
self.__version = VERSION
|
||||
self.__root = r"Software\Microsoft\VisualStudio"
|
||||
self.__root = r'Software\Microsoft\VisualStudio'
|
||||
# self.__macros = MACROS
|
||||
self.__paths = []
|
||||
# target platform (.plat_name is consistent with 'bdist')
|
||||
self.plat_name = None
|
||||
self.__arch = None # deprecated name
|
||||
self.__arch = None # deprecated name
|
||||
self.initialized = False
|
||||
|
||||
def initialize(self, plat_name=None):
|
||||
|
|
@ -344,17 +367,19 @@ class MSVCCompiler(CCompiler) :
|
|||
# sanity check for platforms to prevent obscure errors later.
|
||||
ok_plats = 'win32', 'win-amd64'
|
||||
if plat_name not in ok_plats:
|
||||
raise DistutilsPlatformError("--plat-name must be one of %s" %
|
||||
(ok_plats,))
|
||||
raise DistutilsPlatformError(
|
||||
'--plat-name must be one of %s' %
|
||||
(ok_plats,),
|
||||
)
|
||||
|
||||
if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
|
||||
if 'DISTUTILS_USE_SDK' in os.environ and 'MSSdk' in os.environ and self.find_exe('cl.exe'):
|
||||
# Assume that the SDK set up everything alright; don't try to be
|
||||
# smarter
|
||||
self.cc = "cl.exe"
|
||||
self.linker = "link.exe"
|
||||
self.lib = "lib.exe"
|
||||
self.rc = "rc.exe"
|
||||
self.mc = "mc.exe"
|
||||
self.cc = 'cl.exe'
|
||||
self.linker = 'link.exe'
|
||||
self.lib = 'lib.exe'
|
||||
self.rc = 'rc.exe'
|
||||
self.mc = 'mc.exe'
|
||||
else:
|
||||
# On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
|
||||
# to cross compile, you use 'x86_amd64'.
|
||||
|
|
@ -366,7 +391,7 @@ class MSVCCompiler(CCompiler) :
|
|||
else:
|
||||
# cross compile from win32 -> some 64bit
|
||||
plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
|
||||
PLAT_TO_VCVARS[plat_name]
|
||||
PLAT_TO_VCVARS[plat_name]
|
||||
|
||||
vc_env = query_vcvarsall(VERSION, plat_spec)
|
||||
|
||||
|
|
@ -375,16 +400,18 @@ class MSVCCompiler(CCompiler) :
|
|||
os.environ['include'] = vc_env['include']
|
||||
|
||||
if len(self.__paths) == 0:
|
||||
raise DistutilsPlatformError("Python was built with %s, "
|
||||
"and extensions need to be built with the same "
|
||||
"version of the compiler, but it isn't installed."
|
||||
% self.__product)
|
||||
raise DistutilsPlatformError(
|
||||
'Python was built with %s, '
|
||||
'and extensions need to be built with the same '
|
||||
"version of the compiler, but it isn't installed."
|
||||
% self.__product,
|
||||
)
|
||||
|
||||
self.cc = self.find_exe("cl.exe")
|
||||
self.linker = self.find_exe("link.exe")
|
||||
self.lib = self.find_exe("lib.exe")
|
||||
self.rc = self.find_exe("rc.exe") # resource compiler
|
||||
self.mc = self.find_exe("mc.exe") # message compiler
|
||||
self.cc = self.find_exe('cl.exe')
|
||||
self.linker = self.find_exe('link.exe')
|
||||
self.lib = self.find_exe('lib.exe')
|
||||
self.rc = self.find_exe('rc.exe') # resource compiler
|
||||
self.mc = self.find_exe('mc.exe') # message compiler
|
||||
#self.set_path_env_var('lib')
|
||||
#self.set_path_env_var('include')
|
||||
|
||||
|
|
@ -395,75 +422,99 @@ class MSVCCompiler(CCompiler) :
|
|||
except KeyError:
|
||||
pass
|
||||
self.__paths = normalize_and_reduce_paths(self.__paths)
|
||||
os.environ['path'] = ";".join(self.__paths)
|
||||
os.environ['path'] = ';'.join(self.__paths)
|
||||
|
||||
self.preprocess_options = None
|
||||
if self.__arch == "x86":
|
||||
self.compile_options = [ '/nologo', '/O2', '/MD', '/W3',
|
||||
'/DNDEBUG']
|
||||
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
|
||||
'/Z7', '/D_DEBUG']
|
||||
if self.__arch == 'x86':
|
||||
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', '/O2', '/MD', '/W3', '/GS-' ,
|
||||
'/DNDEBUG']
|
||||
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
|
||||
'/Z7', '/D_DEBUG']
|
||||
self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GS-',
|
||||
'/DNDEBUG',
|
||||
]
|
||||
self.compile_options_debug = [
|
||||
'/nologo', '/Od', '/MDd', '/W3', '/GS-',
|
||||
'/Z7', '/D_DEBUG',
|
||||
]
|
||||
|
||||
self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
|
||||
if self.__version >= 7:
|
||||
self.ldflags_shared_debug = [
|
||||
'/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'
|
||||
]
|
||||
self.ldflags_static = [ '/nologo']
|
||||
'/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG',
|
||||
]
|
||||
self.ldflags_static = ['/nologo']
|
||||
|
||||
self.initialized = True
|
||||
|
||||
# -- Worker methods ------------------------------------------------
|
||||
|
||||
def object_filenames(self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
def object_filenames(
|
||||
self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir='',
|
||||
):
|
||||
# Copied from ccompiler.py, extended to return .res as 'object'-file
|
||||
# for .rc input file
|
||||
if output_dir is None: output_dir = ''
|
||||
if output_dir is None:
|
||||
output_dir = ''
|
||||
obj_names = []
|
||||
for src_name in source_filenames:
|
||||
(base, ext) = os.path.splitext (src_name)
|
||||
base = os.path.splitdrive(base)[1] # Chop off the drive
|
||||
(base, ext) = os.path.splitext(src_name)
|
||||
base = os.path.splitdrive(base)[1] # Chop off the drive
|
||||
base = base[os.path.isabs(base):] # If abs, chop off leading /
|
||||
if ext not in self.src_extensions:
|
||||
# Better to raise an exception instead of silently continuing
|
||||
# and later complain about sources and targets having
|
||||
# different lengths
|
||||
raise CompileError ("Don't know how to compile %s" % src_name)
|
||||
raise CompileError("Don't know how to compile %s" % src_name)
|
||||
if strip_dir:
|
||||
base = os.path.basename (base)
|
||||
base = os.path.basename(base)
|
||||
if ext in self._rc_extensions:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.res_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.res_extension,
|
||||
),
|
||||
)
|
||||
elif ext in self._mc_extensions:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.res_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.res_extension,
|
||||
),
|
||||
)
|
||||
else:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.obj_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.obj_extension,
|
||||
),
|
||||
)
|
||||
return obj_names
|
||||
|
||||
|
||||
def compile(self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None):
|
||||
def compile(
|
||||
self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
compile_info = self._setup_compile(output_dir, macros, include_dirs,
|
||||
sources, depends, extra_postargs)
|
||||
compile_info = self._setup_compile(
|
||||
output_dir, macros, include_dirs,
|
||||
sources, depends, extra_postargs,
|
||||
)
|
||||
macros, objects, extra_postargs, pp_opts, build = compile_info
|
||||
|
||||
compile_opts = extra_preargs or []
|
||||
compile_opts.append ('/c')
|
||||
compile_opts.append('/c')
|
||||
if debug:
|
||||
compile_opts.extend(self.compile_options_debug)
|
||||
else:
|
||||
|
|
@ -481,13 +532,13 @@ class MSVCCompiler(CCompiler) :
|
|||
src = os.path.abspath(src)
|
||||
|
||||
if ext in self._c_extensions:
|
||||
input_opt = "/Tc" + src
|
||||
input_opt = '/Tc' + src
|
||||
elif ext in self._cpp_extensions:
|
||||
input_opt = "/Tp" + src
|
||||
input_opt = '/Tp' + src
|
||||
elif ext in self._rc_extensions:
|
||||
# compile .RC to .RES file
|
||||
input_opt = src
|
||||
output_opt = "/fo" + obj
|
||||
output_opt = '/fo' + obj
|
||||
try:
|
||||
self.spawn([self.rc] + pp_opts +
|
||||
[output_opt] + [input_opt])
|
||||
|
|
@ -512,85 +563,99 @@ class MSVCCompiler(CCompiler) :
|
|||
# first compile .MC to .RC and .H file
|
||||
self.spawn([self.mc] +
|
||||
['-h', h_dir, '-r', rc_dir] + [src])
|
||||
base, _ = os.path.splitext (os.path.basename (src))
|
||||
rc_file = os.path.join (rc_dir, base + '.rc')
|
||||
base, _ = os.path.splitext(os.path.basename(src))
|
||||
rc_file = os.path.join(rc_dir, base + '.rc')
|
||||
# then compile .RC to .RES file
|
||||
self.spawn([self.rc] +
|
||||
["/fo" + obj] + [rc_file])
|
||||
['/fo' + obj] + [rc_file])
|
||||
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
continue
|
||||
else:
|
||||
# how to handle this file?
|
||||
raise CompileError("Don't know how to compile %s to %s"
|
||||
% (src, obj))
|
||||
raise CompileError(
|
||||
"Don't know how to compile %s to %s"
|
||||
% (src, obj),
|
||||
)
|
||||
|
||||
output_opt = "/Fo" + obj
|
||||
output_opt = '/Fo' + obj
|
||||
try:
|
||||
self.spawn([self.cc] + compile_opts + pp_opts +
|
||||
[input_opt, output_opt] +
|
||||
extra_postargs)
|
||||
self.spawn(
|
||||
[self.cc] + compile_opts + pp_opts +
|
||||
[input_opt, output_opt] +
|
||||
extra_postargs,
|
||||
)
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
def create_static_lib(self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None):
|
||||
def create_static_lib(
|
||||
self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
output_filename = self.library_filename(output_libname,
|
||||
output_dir=output_dir)
|
||||
output_filename = self.library_filename(
|
||||
output_libname,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
|
||||
if self._need_link(objects, output_filename):
|
||||
lib_args = objects + ['/OUT:' + output_filename]
|
||||
if debug:
|
||||
pass # XXX what goes here?
|
||||
pass # XXX what goes here?
|
||||
try:
|
||||
self.spawn([self.lib] + lib_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise LibError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
|
||||
def link(self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
def link(
|
||||
self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
fixed_args = self._fix_lib_args(libraries, library_dirs,
|
||||
runtime_library_dirs)
|
||||
fixed_args = self._fix_lib_args(
|
||||
libraries, library_dirs,
|
||||
runtime_library_dirs,
|
||||
)
|
||||
(libraries, library_dirs, runtime_library_dirs) = fixed_args
|
||||
|
||||
if runtime_library_dirs:
|
||||
self.warn ("I don't know what to do with 'runtime_library_dirs': "
|
||||
+ str (runtime_library_dirs))
|
||||
self.warn(
|
||||
"I don't know what to do with 'runtime_library_dirs': " +
|
||||
str(runtime_library_dirs),
|
||||
)
|
||||
|
||||
lib_opts = gen_lib_options(self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
lib_opts = gen_lib_options(
|
||||
self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries,
|
||||
)
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join(output_dir, output_filename)
|
||||
|
||||
|
|
@ -608,10 +673,12 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
export_opts = []
|
||||
for sym in (export_symbols or []):
|
||||
export_opts.append("/EXPORT:" + sym)
|
||||
export_opts.append('/EXPORT:' + sym)
|
||||
|
||||
ld_args = (ldflags + lib_opts + export_opts +
|
||||
objects + ['/OUT:' + output_filename])
|
||||
ld_args = (
|
||||
ldflags + lib_opts + export_opts +
|
||||
objects + ['/OUT:' + output_filename]
|
||||
)
|
||||
|
||||
# The MSVC linker generates .lib and .exp files, which cannot be
|
||||
# suppressed by any linker switches. The .lib files may even be
|
||||
|
|
@ -621,11 +688,13 @@ class MSVCCompiler(CCompiler) :
|
|||
build_temp = os.path.dirname(objects[0])
|
||||
if export_symbols is not None:
|
||||
(dll_name, dll_ext) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
os.path.basename(output_filename),
|
||||
)
|
||||
implib_file = os.path.join(
|
||||
build_temp,
|
||||
self.library_filename(dll_name))
|
||||
ld_args.append ('/IMPLIB:' + implib_file)
|
||||
self.library_filename(dll_name),
|
||||
)
|
||||
ld_args.append('/IMPLIB:' + implib_file)
|
||||
|
||||
self.manifest_setup_ldargs(output_filename, build_temp, ld_args)
|
||||
|
||||
|
|
@ -648,14 +717,16 @@ class MSVCCompiler(CCompiler) :
|
|||
mfinfo = self.manifest_get_embed_info(target_desc, ld_args)
|
||||
if mfinfo is not None:
|
||||
mffilename, mfid = mfinfo
|
||||
out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
|
||||
out_arg = '-outputresource:{};{}'.format(output_filename, mfid)
|
||||
try:
|
||||
self.spawn(['mt.exe', '-nologo', '-manifest',
|
||||
mffilename, out_arg])
|
||||
self.spawn([
|
||||
'mt.exe', '-nologo', '-manifest',
|
||||
mffilename, out_arg,
|
||||
])
|
||||
except DistutilsExecError as msg:
|
||||
raise LinkError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
def manifest_setup_ldargs(self, output_filename, build_temp, ld_args):
|
||||
# If we need a manifest at all, an embedded manifest is recommended.
|
||||
|
|
@ -665,8 +736,9 @@ class MSVCCompiler(CCompiler) :
|
|||
# Ask the linker to generate the manifest in the temp dir, so
|
||||
# we can check it, and possibly embed it, later.
|
||||
temp_manifest = os.path.join(
|
||||
build_temp,
|
||||
os.path.basename(output_filename) + ".manifest")
|
||||
build_temp,
|
||||
os.path.basename(output_filename) + '.manifest',
|
||||
)
|
||||
ld_args.append('/MANIFESTFILE:' + temp_manifest)
|
||||
|
||||
def manifest_get_embed_info(self, target_desc, ld_args):
|
||||
|
|
@ -675,8 +747,8 @@ class MSVCCompiler(CCompiler) :
|
|||
# should be embedded. See http://bugs.python.org/issue7833 for why
|
||||
# we want to avoid any manifest for extension modules if we can)
|
||||
for arg in ld_args:
|
||||
if arg.startswith("/MANIFESTFILE:"):
|
||||
temp_manifest = arg.split(":", 1)[1]
|
||||
if arg.startswith('/MANIFESTFILE:'):
|
||||
temp_manifest = arg.split(':', 1)[1]
|
||||
break
|
||||
else:
|
||||
# no /MANIFESTFILE so nothing to do.
|
||||
|
|
@ -709,17 +781,19 @@ class MSVCCompiler(CCompiler) :
|
|||
finally:
|
||||
manifest_f.close()
|
||||
pattern = re.compile(
|
||||
r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
|
||||
r"""<assemblyIdentity.*?name=("|')Microsoft\."""
|
||||
r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
|
||||
re.DOTALL)
|
||||
manifest_buf = re.sub(pattern, "", manifest_buf)
|
||||
pattern = r"<dependentAssembly>\s*</dependentAssembly>"
|
||||
manifest_buf = re.sub(pattern, "", manifest_buf)
|
||||
re.DOTALL,
|
||||
)
|
||||
manifest_buf = re.sub(pattern, '', manifest_buf)
|
||||
pattern = r'<dependentAssembly>\s*</dependentAssembly>'
|
||||
manifest_buf = re.sub(pattern, '', manifest_buf)
|
||||
# Now see if any other assemblies are referenced - if not, we
|
||||
# don't want a manifest embedded.
|
||||
pattern = re.compile(
|
||||
r"""<assemblyIdentity.*?name=(?:"|')(.+?)(?:"|')"""
|
||||
r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL)
|
||||
r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL,
|
||||
)
|
||||
if re.search(pattern, manifest_buf) is None:
|
||||
return None
|
||||
|
||||
|
|
@ -737,26 +811,26 @@ class MSVCCompiler(CCompiler) :
|
|||
# ccompiler.py.
|
||||
|
||||
def library_dir_option(self, dir):
|
||||
return "/LIBPATH:" + dir
|
||||
return '/LIBPATH:' + dir
|
||||
|
||||
def runtime_library_dir_option(self, dir):
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to set runtime library search path for MSVC++")
|
||||
"don't know how to set runtime library search path for MSVC++",
|
||||
)
|
||||
|
||||
def library_option(self, lib):
|
||||
return self.library_filename(lib)
|
||||
|
||||
|
||||
def find_library_file(self, dirs, lib, debug=0):
|
||||
# Prefer a debugging library if found (and requested), but deal
|
||||
# with it if we don't have one.
|
||||
if debug:
|
||||
try_names = [lib + "_d", lib]
|
||||
try_names = [lib + '_d', lib]
|
||||
else:
|
||||
try_names = [lib]
|
||||
for dir in dirs:
|
||||
for name in try_names:
|
||||
libfile = os.path.join(dir, self.library_filename (name))
|
||||
libfile = os.path.join(dir, self.library_filename(name))
|
||||
if os.path.exists(libfile):
|
||||
return libfile
|
||||
else:
|
||||
|
|
@ -781,7 +855,7 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
# didn't find it; try existing path
|
||||
for p in os.environ['Path'].split(';'):
|
||||
fn = os.path.join(os.path.abspath(p),exe)
|
||||
fn = os.path.join(os.path.abspath(p), exe)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
|
||||
|
|
|
|||
|
|
@ -3,18 +3,22 @@
|
|||
Contains MSVCCompiler, an implementation of the abstract CCompiler class
|
||||
for the Microsoft Visual Studio.
|
||||
"""
|
||||
|
||||
# Written by Perry Stoll
|
||||
# hacked by Robin Becker and Thomas Heller to do a better job of
|
||||
# finding DevStudio (through the registry)
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import sys, os
|
||||
from distutils.errors import \
|
||||
DistutilsExecError, DistutilsPlatformError, \
|
||||
CompileError, LibError, LinkError
|
||||
from distutils.ccompiler import \
|
||||
CCompiler, gen_lib_options
|
||||
from distutils import log
|
||||
from distutils.ccompiler import CCompiler
|
||||
from distutils.ccompiler import gen_lib_options
|
||||
from distutils.errors import CompileError
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
from distutils.errors import LibError
|
||||
from distutils.errors import LinkError
|
||||
|
||||
_can_read_reg = False
|
||||
try:
|
||||
|
|
@ -40,17 +44,22 @@ except ImportError:
|
|||
RegEnumValue = win32api.RegEnumValue
|
||||
RegError = win32api.error
|
||||
except ImportError:
|
||||
log.info("Warning: Can't read registry to find the "
|
||||
"necessary compiler setting\n"
|
||||
"Make sure that Python modules winreg, "
|
||||
"win32api or win32con are installed.")
|
||||
log.info(
|
||||
"Warning: Can't read registry to find the "
|
||||
'necessary compiler setting\n'
|
||||
'Make sure that Python modules winreg, '
|
||||
'win32api or win32con are installed.',
|
||||
)
|
||||
pass
|
||||
|
||||
if _can_read_reg:
|
||||
HKEYS = (hkey_mod.HKEY_USERS,
|
||||
hkey_mod.HKEY_CURRENT_USER,
|
||||
hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
hkey_mod.HKEY_CLASSES_ROOT)
|
||||
HKEYS = (
|
||||
hkey_mod.HKEY_USERS,
|
||||
hkey_mod.HKEY_CURRENT_USER,
|
||||
hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
hkey_mod.HKEY_CLASSES_ROOT,
|
||||
)
|
||||
|
||||
|
||||
def read_keys(base, key):
|
||||
"""Return list of registry keys."""
|
||||
|
|
@ -69,6 +78,7 @@ def read_keys(base, key):
|
|||
i += 1
|
||||
return L
|
||||
|
||||
|
||||
def read_values(base, key):
|
||||
"""Return dict of registry keys and values.
|
||||
|
||||
|
|
@ -90,15 +100,17 @@ def read_values(base, key):
|
|||
i += 1
|
||||
return d
|
||||
|
||||
|
||||
def convert_mbcs(s):
|
||||
dec = getattr(s, "decode", None)
|
||||
dec = getattr(s, 'decode', None)
|
||||
if dec is not None:
|
||||
try:
|
||||
s = dec("mbcs")
|
||||
s = dec('mbcs')
|
||||
except UnicodeError:
|
||||
pass
|
||||
return s
|
||||
|
||||
|
||||
class MacroExpander:
|
||||
def __init__(self, version):
|
||||
self.macros = {}
|
||||
|
|
@ -108,54 +120,56 @@ class MacroExpander:
|
|||
for base in HKEYS:
|
||||
d = read_values(base, path)
|
||||
if d:
|
||||
self.macros["$(%s)" % macro] = d[key]
|
||||
self.macros['$(%s)' % macro] = d[key]
|
||||
break
|
||||
|
||||
def load_macros(self, version):
|
||||
vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
|
||||
self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
|
||||
self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
|
||||
net = r"Software\Microsoft\.NETFramework"
|
||||
self.set_macro("FrameworkDir", net, "installroot")
|
||||
vsbase = r'Software\Microsoft\VisualStudio\%0.1f' % version
|
||||
self.set_macro('VCInstallDir', vsbase + r'\Setup\VC', 'productdir')
|
||||
self.set_macro('VSInstallDir', vsbase + r'\Setup\VS', 'productdir')
|
||||
net = r'Software\Microsoft\.NETFramework'
|
||||
self.set_macro('FrameworkDir', net, 'installroot')
|
||||
try:
|
||||
if version > 7.0:
|
||||
self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
|
||||
self.set_macro('FrameworkSDKDir', net, 'sdkinstallrootv1.1')
|
||||
else:
|
||||
self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
|
||||
except KeyError as exc: #
|
||||
self.set_macro('FrameworkSDKDir', net, 'sdkinstallroot')
|
||||
except KeyError as exc:
|
||||
raise DistutilsPlatformError(
|
||||
"""Python was built with Visual Studio 2003;
|
||||
"""Python was built with Visual Studio 2003;
|
||||
extensions must be built with a compiler than can generate compatible binaries.
|
||||
Visual Studio 2003 was not found on this system. If you have Cygwin installed,
|
||||
you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
|
||||
you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""",
|
||||
)
|
||||
|
||||
p = r"Software\Microsoft\NET Framework Setup\Product"
|
||||
p = r'Software\Microsoft\NET Framework Setup\Product'
|
||||
for base in HKEYS:
|
||||
try:
|
||||
h = RegOpenKeyEx(base, p)
|
||||
except RegError:
|
||||
continue
|
||||
key = RegEnumKey(h, 0)
|
||||
d = read_values(base, r"%s\%s" % (p, key))
|
||||
self.macros["$(FrameworkVersion)"] = d["version"]
|
||||
d = read_values(base, r'{}\{}'.format(p, key))
|
||||
self.macros['$(FrameworkVersion)'] = d['version']
|
||||
|
||||
def sub(self, s):
|
||||
for k, v in self.macros.items():
|
||||
s = s.replace(k, v)
|
||||
return s
|
||||
|
||||
|
||||
def get_build_version():
|
||||
"""Return the version of MSVC that was used to build Python.
|
||||
|
||||
For Python 2.3 and up, the version number is included in
|
||||
sys.version. For earlier versions, assume the compiler is MSVC 6.
|
||||
"""
|
||||
prefix = "MSC v."
|
||||
prefix = 'MSC v.'
|
||||
i = sys.version.find(prefix)
|
||||
if i == -1:
|
||||
return 6
|
||||
i = i + len(prefix)
|
||||
s, rest = sys.version[i:].split(" ", 1)
|
||||
s, rest = sys.version[i:].split(' ', 1)
|
||||
majorVersion = int(s[:-2]) - 6
|
||||
if majorVersion >= 13:
|
||||
# v13 was skipped and should be v14
|
||||
|
|
@ -169,18 +183,20 @@ def get_build_version():
|
|||
# else we don't know what version of the compiler this is
|
||||
return None
|
||||
|
||||
|
||||
def get_build_architecture():
|
||||
"""Return the processor architecture.
|
||||
|
||||
Possible results are "Intel" or "AMD64".
|
||||
"""
|
||||
|
||||
prefix = " bit ("
|
||||
prefix = ' bit ('
|
||||
i = sys.version.find(prefix)
|
||||
if i == -1:
|
||||
return "Intel"
|
||||
j = sys.version.find(")", i)
|
||||
return sys.version[i+len(prefix):j]
|
||||
return 'Intel'
|
||||
j = sys.version.find(')', i)
|
||||
return sys.version[i + len(prefix):j]
|
||||
|
||||
|
||||
def normalize_and_reduce_paths(paths):
|
||||
"""Return a list of normalized paths with duplicates removed.
|
||||
|
|
@ -197,7 +213,7 @@ def normalize_and_reduce_paths(paths):
|
|||
return reduced_paths
|
||||
|
||||
|
||||
class MSVCCompiler(CCompiler) :
|
||||
class MSVCCompiler(CCompiler):
|
||||
"""Concrete class that implements an interface to Microsoft Visual C++,
|
||||
as defined by the CCompiler abstract class."""
|
||||
|
||||
|
|
@ -218,8 +234,10 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
# Needed for the filename generation methods provided by the
|
||||
# base class, CCompiler.
|
||||
src_extensions = (_c_extensions + _cpp_extensions +
|
||||
_rc_extensions + _mc_extensions)
|
||||
src_extensions = (
|
||||
_c_extensions + _cpp_extensions +
|
||||
_rc_extensions + _mc_extensions
|
||||
)
|
||||
res_extension = '.res'
|
||||
obj_extension = '.obj'
|
||||
static_lib_extension = '.lib'
|
||||
|
|
@ -228,47 +246,49 @@ class MSVCCompiler(CCompiler) :
|
|||
exe_extension = '.exe'
|
||||
|
||||
def __init__(self, verbose=0, dry_run=0, force=0):
|
||||
CCompiler.__init__ (self, verbose, dry_run, force)
|
||||
CCompiler.__init__(self, verbose, dry_run, force)
|
||||
self.__version = get_build_version()
|
||||
self.__arch = get_build_architecture()
|
||||
if self.__arch == "Intel":
|
||||
if self.__arch == 'Intel':
|
||||
# x86
|
||||
if self.__version >= 7:
|
||||
self.__root = r"Software\Microsoft\VisualStudio"
|
||||
self.__root = r'Software\Microsoft\VisualStudio'
|
||||
self.__macros = MacroExpander(self.__version)
|
||||
else:
|
||||
self.__root = r"Software\Microsoft\Devstudio"
|
||||
self.__product = "Visual Studio version %s" % self.__version
|
||||
self.__root = r'Software\Microsoft\Devstudio'
|
||||
self.__product = 'Visual Studio version %s' % self.__version
|
||||
else:
|
||||
# Win64. Assume this was built with the platform SDK
|
||||
self.__product = "Microsoft SDK compiler %s" % (self.__version + 6)
|
||||
self.__product = 'Microsoft SDK compiler %s' % (self.__version + 6)
|
||||
|
||||
self.initialized = False
|
||||
|
||||
def initialize(self):
|
||||
self.__paths = []
|
||||
if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
|
||||
if 'DISTUTILS_USE_SDK' in os.environ and 'MSSdk' in os.environ and self.find_exe('cl.exe'):
|
||||
# Assume that the SDK set up everything alright; don't try to be
|
||||
# smarter
|
||||
self.cc = "cl.exe"
|
||||
self.linker = "link.exe"
|
||||
self.lib = "lib.exe"
|
||||
self.rc = "rc.exe"
|
||||
self.mc = "mc.exe"
|
||||
self.cc = 'cl.exe'
|
||||
self.linker = 'link.exe'
|
||||
self.lib = 'lib.exe'
|
||||
self.rc = 'rc.exe'
|
||||
self.mc = 'mc.exe'
|
||||
else:
|
||||
self.__paths = self.get_msvc_paths("path")
|
||||
self.__paths = self.get_msvc_paths('path')
|
||||
|
||||
if len(self.__paths) == 0:
|
||||
raise DistutilsPlatformError("Python was built with %s, "
|
||||
"and extensions need to be built with the same "
|
||||
"version of the compiler, but it isn't installed."
|
||||
% self.__product)
|
||||
raise DistutilsPlatformError(
|
||||
'Python was built with %s, '
|
||||
'and extensions need to be built with the same '
|
||||
"version of the compiler, but it isn't installed."
|
||||
% self.__product,
|
||||
)
|
||||
|
||||
self.cc = self.find_exe("cl.exe")
|
||||
self.linker = self.find_exe("link.exe")
|
||||
self.lib = self.find_exe("lib.exe")
|
||||
self.rc = self.find_exe("rc.exe") # resource compiler
|
||||
self.mc = self.find_exe("mc.exe") # message compiler
|
||||
self.cc = self.find_exe('cl.exe')
|
||||
self.linker = self.find_exe('link.exe')
|
||||
self.lib = self.find_exe('lib.exe')
|
||||
self.rc = self.find_exe('rc.exe') # resource compiler
|
||||
self.mc = self.find_exe('mc.exe') # message compiler
|
||||
self.set_path_env_var('lib')
|
||||
self.set_path_env_var('include')
|
||||
|
||||
|
|
@ -279,79 +299,103 @@ class MSVCCompiler(CCompiler) :
|
|||
except KeyError:
|
||||
pass
|
||||
self.__paths = normalize_and_reduce_paths(self.__paths)
|
||||
os.environ['path'] = ";".join(self.__paths)
|
||||
os.environ['path'] = ';'.join(self.__paths)
|
||||
|
||||
self.preprocess_options = None
|
||||
if self.__arch == "Intel":
|
||||
self.compile_options = [ '/nologo', '/O2', '/MD', '/W3', '/GX' ,
|
||||
'/DNDEBUG']
|
||||
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
|
||||
'/Z7', '/D_DEBUG']
|
||||
if self.__arch == 'Intel':
|
||||
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', '/O2', '/MD', '/W3', '/GS-' ,
|
||||
'/DNDEBUG']
|
||||
self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
|
||||
'/Z7', '/D_DEBUG']
|
||||
self.compile_options = ['/nologo', '/O2', '/MD', '/W3', '/GS-',
|
||||
'/DNDEBUG',
|
||||
]
|
||||
self.compile_options_debug = [
|
||||
'/nologo', '/Od', '/MDd', '/W3', '/GS-',
|
||||
'/Z7', '/D_DEBUG',
|
||||
]
|
||||
|
||||
self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
|
||||
if self.__version >= 7:
|
||||
self.ldflags_shared_debug = [
|
||||
'/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'
|
||||
]
|
||||
'/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG',
|
||||
]
|
||||
else:
|
||||
self.ldflags_shared_debug = [
|
||||
'/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
|
||||
]
|
||||
self.ldflags_static = [ '/nologo']
|
||||
'/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG',
|
||||
]
|
||||
self.ldflags_static = ['/nologo']
|
||||
|
||||
self.initialized = True
|
||||
|
||||
# -- Worker methods ------------------------------------------------
|
||||
|
||||
def object_filenames(self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir=''):
|
||||
def object_filenames(
|
||||
self,
|
||||
source_filenames,
|
||||
strip_dir=0,
|
||||
output_dir='',
|
||||
):
|
||||
# Copied from ccompiler.py, extended to return .res as 'object'-file
|
||||
# for .rc input file
|
||||
if output_dir is None: output_dir = ''
|
||||
if output_dir is None:
|
||||
output_dir = ''
|
||||
obj_names = []
|
||||
for src_name in source_filenames:
|
||||
(base, ext) = os.path.splitext (src_name)
|
||||
base = os.path.splitdrive(base)[1] # Chop off the drive
|
||||
(base, ext) = os.path.splitext(src_name)
|
||||
base = os.path.splitdrive(base)[1] # Chop off the drive
|
||||
base = base[os.path.isabs(base):] # If abs, chop off leading /
|
||||
if ext not in self.src_extensions:
|
||||
# Better to raise an exception instead of silently continuing
|
||||
# and later complain about sources and targets having
|
||||
# different lengths
|
||||
raise CompileError ("Don't know how to compile %s" % src_name)
|
||||
raise CompileError("Don't know how to compile %s" % src_name)
|
||||
if strip_dir:
|
||||
base = os.path.basename (base)
|
||||
base = os.path.basename(base)
|
||||
if ext in self._rc_extensions:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.res_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.res_extension,
|
||||
),
|
||||
)
|
||||
elif ext in self._mc_extensions:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.res_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.res_extension,
|
||||
),
|
||||
)
|
||||
else:
|
||||
obj_names.append (os.path.join (output_dir,
|
||||
base + self.obj_extension))
|
||||
obj_names.append(
|
||||
os.path.join(
|
||||
output_dir,
|
||||
base + self.obj_extension,
|
||||
),
|
||||
)
|
||||
return obj_names
|
||||
|
||||
|
||||
def compile(self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None):
|
||||
def compile(
|
||||
self, sources,
|
||||
output_dir=None, macros=None, include_dirs=None, debug=0,
|
||||
extra_preargs=None, extra_postargs=None, depends=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
compile_info = self._setup_compile(output_dir, macros, include_dirs,
|
||||
sources, depends, extra_postargs)
|
||||
compile_info = self._setup_compile(
|
||||
output_dir, macros, include_dirs,
|
||||
sources, depends, extra_postargs,
|
||||
)
|
||||
macros, objects, extra_postargs, pp_opts, build = compile_info
|
||||
|
||||
compile_opts = extra_preargs or []
|
||||
compile_opts.append ('/c')
|
||||
compile_opts.append('/c')
|
||||
if debug:
|
||||
compile_opts.extend(self.compile_options_debug)
|
||||
else:
|
||||
|
|
@ -369,13 +413,13 @@ class MSVCCompiler(CCompiler) :
|
|||
src = os.path.abspath(src)
|
||||
|
||||
if ext in self._c_extensions:
|
||||
input_opt = "/Tc" + src
|
||||
input_opt = '/Tc' + src
|
||||
elif ext in self._cpp_extensions:
|
||||
input_opt = "/Tp" + src
|
||||
input_opt = '/Tp' + src
|
||||
elif ext in self._rc_extensions:
|
||||
# compile .RC to .RES file
|
||||
input_opt = src
|
||||
output_opt = "/fo" + obj
|
||||
output_opt = '/fo' + obj
|
||||
try:
|
||||
self.spawn([self.rc] + pp_opts +
|
||||
[output_opt] + [input_opt])
|
||||
|
|
@ -400,85 +444,99 @@ class MSVCCompiler(CCompiler) :
|
|||
# first compile .MC to .RC and .H file
|
||||
self.spawn([self.mc] +
|
||||
['-h', h_dir, '-r', rc_dir] + [src])
|
||||
base, _ = os.path.splitext (os.path.basename (src))
|
||||
rc_file = os.path.join (rc_dir, base + '.rc')
|
||||
base, _ = os.path.splitext(os.path.basename(src))
|
||||
rc_file = os.path.join(rc_dir, base + '.rc')
|
||||
# then compile .RC to .RES file
|
||||
self.spawn([self.rc] +
|
||||
["/fo" + obj] + [rc_file])
|
||||
['/fo' + obj] + [rc_file])
|
||||
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
continue
|
||||
else:
|
||||
# how to handle this file?
|
||||
raise CompileError("Don't know how to compile %s to %s"
|
||||
% (src, obj))
|
||||
raise CompileError(
|
||||
"Don't know how to compile %s to %s"
|
||||
% (src, obj),
|
||||
)
|
||||
|
||||
output_opt = "/Fo" + obj
|
||||
output_opt = '/Fo' + obj
|
||||
try:
|
||||
self.spawn([self.cc] + compile_opts + pp_opts +
|
||||
[input_opt, output_opt] +
|
||||
extra_postargs)
|
||||
self.spawn(
|
||||
[self.cc] + compile_opts + pp_opts +
|
||||
[input_opt, output_opt] +
|
||||
extra_postargs,
|
||||
)
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
|
||||
return objects
|
||||
|
||||
|
||||
def create_static_lib(self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None):
|
||||
def create_static_lib(
|
||||
self,
|
||||
objects,
|
||||
output_libname,
|
||||
output_dir=None,
|
||||
debug=0,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
output_filename = self.library_filename(output_libname,
|
||||
output_dir=output_dir)
|
||||
output_filename = self.library_filename(
|
||||
output_libname,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
|
||||
if self._need_link(objects, output_filename):
|
||||
lib_args = objects + ['/OUT:' + output_filename]
|
||||
if debug:
|
||||
pass # XXX what goes here?
|
||||
pass # XXX what goes here?
|
||||
try:
|
||||
self.spawn([self.lib] + lib_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise LibError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
|
||||
def link(self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None):
|
||||
def link(
|
||||
self,
|
||||
target_desc,
|
||||
objects,
|
||||
output_filename,
|
||||
output_dir=None,
|
||||
libraries=None,
|
||||
library_dirs=None,
|
||||
runtime_library_dirs=None,
|
||||
export_symbols=None,
|
||||
debug=0,
|
||||
extra_preargs=None,
|
||||
extra_postargs=None,
|
||||
build_temp=None,
|
||||
target_lang=None,
|
||||
):
|
||||
|
||||
if not self.initialized:
|
||||
self.initialize()
|
||||
(objects, output_dir) = self._fix_object_args(objects, output_dir)
|
||||
fixed_args = self._fix_lib_args(libraries, library_dirs,
|
||||
runtime_library_dirs)
|
||||
fixed_args = self._fix_lib_args(
|
||||
libraries, library_dirs,
|
||||
runtime_library_dirs,
|
||||
)
|
||||
(libraries, library_dirs, runtime_library_dirs) = fixed_args
|
||||
|
||||
if runtime_library_dirs:
|
||||
self.warn ("I don't know what to do with 'runtime_library_dirs': "
|
||||
+ str (runtime_library_dirs))
|
||||
self.warn(
|
||||
"I don't know what to do with 'runtime_library_dirs': " +
|
||||
str(runtime_library_dirs),
|
||||
)
|
||||
|
||||
lib_opts = gen_lib_options(self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
lib_opts = gen_lib_options(
|
||||
self,
|
||||
library_dirs, runtime_library_dirs,
|
||||
libraries,
|
||||
)
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join(output_dir, output_filename)
|
||||
|
||||
|
|
@ -496,10 +554,12 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
export_opts = []
|
||||
for sym in (export_symbols or []):
|
||||
export_opts.append("/EXPORT:" + sym)
|
||||
export_opts.append('/EXPORT:' + sym)
|
||||
|
||||
ld_args = (ldflags + lib_opts + export_opts +
|
||||
objects + ['/OUT:' + output_filename])
|
||||
ld_args = (
|
||||
ldflags + lib_opts + export_opts +
|
||||
objects + ['/OUT:' + output_filename]
|
||||
)
|
||||
|
||||
# The MSVC linker generates .lib and .exp files, which cannot be
|
||||
# suppressed by any linker switches. The .lib files may even be
|
||||
|
|
@ -508,11 +568,13 @@ class MSVCCompiler(CCompiler) :
|
|||
# builds, they can go into the same directory.
|
||||
if export_symbols is not None:
|
||||
(dll_name, dll_ext) = os.path.splitext(
|
||||
os.path.basename(output_filename))
|
||||
os.path.basename(output_filename),
|
||||
)
|
||||
implib_file = os.path.join(
|
||||
os.path.dirname(objects[0]),
|
||||
self.library_filename(dll_name))
|
||||
ld_args.append ('/IMPLIB:' + implib_file)
|
||||
self.library_filename(dll_name),
|
||||
)
|
||||
ld_args.append('/IMPLIB:' + implib_file)
|
||||
|
||||
if extra_preargs:
|
||||
ld_args[:0] = extra_preargs
|
||||
|
|
@ -526,34 +588,33 @@ class MSVCCompiler(CCompiler) :
|
|||
raise LinkError(msg)
|
||||
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
# These are all used by the 'gen_lib_options() function, in
|
||||
# ccompiler.py.
|
||||
|
||||
def library_dir_option(self, dir):
|
||||
return "/LIBPATH:" + dir
|
||||
return '/LIBPATH:' + dir
|
||||
|
||||
def runtime_library_dir_option(self, dir):
|
||||
raise DistutilsPlatformError(
|
||||
"don't know how to set runtime library search path for MSVC++")
|
||||
"don't know how to set runtime library search path for MSVC++",
|
||||
)
|
||||
|
||||
def library_option(self, lib):
|
||||
return self.library_filename(lib)
|
||||
|
||||
|
||||
def find_library_file(self, dirs, lib, debug=0):
|
||||
# Prefer a debugging library if found (and requested), but deal
|
||||
# with it if we don't have one.
|
||||
if debug:
|
||||
try_names = [lib + "_d", lib]
|
||||
try_names = [lib + '_d', lib]
|
||||
else:
|
||||
try_names = [lib]
|
||||
for dir in dirs:
|
||||
for name in try_names:
|
||||
libfile = os.path.join(dir, self.library_filename (name))
|
||||
libfile = os.path.join(dir, self.library_filename(name))
|
||||
if os.path.exists(libfile):
|
||||
return libfile
|
||||
else:
|
||||
|
|
@ -578,7 +639,7 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
# didn't find it; try existing path
|
||||
for p in os.environ['Path'].split(';'):
|
||||
fn = os.path.join(os.path.abspath(p),exe)
|
||||
fn = os.path.join(os.path.abspath(p), exe)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
|
||||
|
|
@ -593,30 +654,36 @@ class MSVCCompiler(CCompiler) :
|
|||
if not _can_read_reg:
|
||||
return []
|
||||
|
||||
path = path + " dirs"
|
||||
path = path + ' dirs'
|
||||
if self.__version >= 7:
|
||||
key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
|
||||
% (self.__root, self.__version))
|
||||
key = (
|
||||
r'%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories'
|
||||
% (self.__root, self.__version)
|
||||
)
|
||||
else:
|
||||
key = (r"%s\6.0\Build System\Components\Platforms"
|
||||
r"\Win32 (%s)\Directories" % (self.__root, platform))
|
||||
key = (
|
||||
r'%s\6.0\Build System\Components\Platforms'
|
||||
r'\Win32 (%s)\Directories' % (self.__root, platform)
|
||||
)
|
||||
|
||||
for base in HKEYS:
|
||||
d = read_values(base, key)
|
||||
if d:
|
||||
if self.__version >= 7:
|
||||
return self.__macros.sub(d[path]).split(";")
|
||||
return self.__macros.sub(d[path]).split(';')
|
||||
else:
|
||||
return d[path].split(";")
|
||||
return d[path].split(';')
|
||||
# MSVC 6 seems to create the registry entries we need only when
|
||||
# the GUI is run.
|
||||
if self.__version == 6:
|
||||
for base in HKEYS:
|
||||
if read_values(base, r"%s\6.0" % self.__root) is not None:
|
||||
self.warn("It seems you have Visual Studio 6 installed, "
|
||||
"but the expected registry settings are not present.\n"
|
||||
"You must at least run the Visual Studio GUI once "
|
||||
"so that these entries are created.")
|
||||
if read_values(base, r'%s\6.0' % self.__root) is not None:
|
||||
self.warn(
|
||||
'It seems you have Visual Studio 6 installed, '
|
||||
'but the expected registry settings are not present.\n'
|
||||
'You must at least run the Visual Studio GUI once '
|
||||
'so that these entries are created.',
|
||||
)
|
||||
break
|
||||
return []
|
||||
|
||||
|
|
@ -627,8 +694,8 @@ class MSVCCompiler(CCompiler) :
|
|||
commands.
|
||||
"""
|
||||
|
||||
if name == "lib":
|
||||
p = self.get_msvc_paths("library")
|
||||
if name == 'lib':
|
||||
p = self.get_msvc_paths('library')
|
||||
else:
|
||||
p = self.get_msvc_paths(name)
|
||||
if p:
|
||||
|
|
@ -636,7 +703,7 @@ class MSVCCompiler(CCompiler) :
|
|||
|
||||
|
||||
if get_build_version() >= 8.0:
|
||||
log.debug("Importing new compiler from distutils.msvc9compiler")
|
||||
log.debug('Importing new compiler from distutils.msvc9compiler')
|
||||
OldMSVCCompiler = MSVCCompiler
|
||||
from distutils.msvc9compiler import MSVCCompiler
|
||||
# get_build_architecture not really relevant now we support cross-compile
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import sys
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def __optim_args_from_interpreter_flags():
|
||||
|
|
@ -8,12 +10,12 @@ def __optim_args_from_interpreter_flags():
|
|||
args = []
|
||||
value = sys.flags.optimize
|
||||
if value > 0:
|
||||
args.append("-" + "O" * value)
|
||||
args.append('-' + 'O' * value)
|
||||
return args
|
||||
|
||||
|
||||
_optim_args_from_interpreter_flags = getattr(
|
||||
subprocess,
|
||||
"_optim_args_from_interpreter_flags",
|
||||
'_optim_args_from_interpreter_flags',
|
||||
__optim_args_from_interpreter_flags,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
|
||||
def aix_platform(osname, version, release):
|
||||
try:
|
||||
import _aix_support
|
||||
return _aix_support.aix_platform()
|
||||
except ImportError:
|
||||
pass
|
||||
return "%s-%s.%s" % (osname, version, release)
|
||||
return '{}-{}.{}'.format(osname, version, release)
|
||||
|
|
|
|||
|
|
@ -5,14 +5,16 @@ specific functions for launching another program in a sub-process.
|
|||
Also provides the 'find_executable()' to search the path for a given
|
||||
executable name.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from distutils.errors import DistutilsPlatformError, DistutilsExecError
|
||||
from distutils.debug import DEBUG
|
||||
from distutils import log
|
||||
from distutils.debug import DEBUG
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
|
||||
|
||||
def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):
|
||||
|
|
@ -60,13 +62,15 @@ def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None):
|
|||
if not DEBUG:
|
||||
cmd = cmd[0]
|
||||
raise DistutilsExecError(
|
||||
"command %r failed: %s" % (cmd, exc.args[-1])) from exc
|
||||
'command {!r} failed: {}'.format(cmd, exc.args[-1]),
|
||||
) from exc
|
||||
|
||||
if exitcode:
|
||||
if not DEBUG:
|
||||
cmd = cmd[0]
|
||||
raise DistutilsExecError(
|
||||
"command %r failed with exit code %s" % (cmd, exitcode))
|
||||
'command {!r} failed with exit code {}'.format(cmd, exitcode),
|
||||
)
|
||||
|
||||
|
||||
def find_executable(executable, path=None):
|
||||
|
|
@ -86,7 +90,7 @@ def find_executable(executable, path=None):
|
|||
path = os.environ.get('PATH', None)
|
||||
if path is None:
|
||||
try:
|
||||
path = os.confstr("CS_PATH")
|
||||
path = os.confstr('CS_PATH')
|
||||
except (AttributeError, ValueError):
|
||||
# os.confstr() or CS_PATH is not available
|
||||
path = os.defpath
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ available.
|
|||
Written by: Fred L. Drake, Jr.
|
||||
Email: <fdrake@acm.org>
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import _imp
|
||||
import os
|
||||
|
|
@ -27,8 +28,8 @@ BASE_EXEC_PREFIX = os.path.normpath(sys.base_exec_prefix)
|
|||
# Path to the base directory of the project. On Windows the binary may
|
||||
# live in project/PCbuild/win32 or project/PCbuild/amd64.
|
||||
# set for cross builds
|
||||
if "_PYTHON_PROJECT_BASE" in os.environ:
|
||||
project_base = os.path.abspath(os.environ["_PYTHON_PROJECT_BASE"])
|
||||
if '_PYTHON_PROJECT_BASE' in os.environ:
|
||||
project_base = os.path.abspath(os.environ['_PYTHON_PROJECT_BASE'])
|
||||
else:
|
||||
if sys.executable:
|
||||
project_base = os.path.dirname(os.path.abspath(sys.executable))
|
||||
|
|
@ -42,27 +43,31 @@ else:
|
|||
# building an extension with an un-installed Python, so we use
|
||||
# different (hard-wired) directories.
|
||||
def _is_python_source_dir(d):
|
||||
for fn in ("Setup", "Setup.local"):
|
||||
if os.path.isfile(os.path.join(d, "Modules", fn)):
|
||||
for fn in ('Setup', 'Setup.local'):
|
||||
if os.path.isfile(os.path.join(d, 'Modules', fn)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
_sys_home = getattr(sys, '_home', None)
|
||||
|
||||
if os.name == 'nt':
|
||||
def _fix_pcbuild(d):
|
||||
if d and os.path.normcase(d).startswith(
|
||||
os.path.normcase(os.path.join(PREFIX, "PCbuild"))):
|
||||
os.path.normcase(os.path.join(PREFIX, 'PCbuild')),
|
||||
):
|
||||
return PREFIX
|
||||
return d
|
||||
project_base = _fix_pcbuild(project_base)
|
||||
_sys_home = _fix_pcbuild(_sys_home)
|
||||
|
||||
|
||||
def _python_build():
|
||||
if _sys_home:
|
||||
return _is_python_source_dir(_sys_home)
|
||||
return _is_python_source_dir(project_base)
|
||||
|
||||
|
||||
python_build = _python_build()
|
||||
|
||||
|
||||
|
|
@ -78,6 +83,7 @@ except AttributeError:
|
|||
# this attribute, which is fine.
|
||||
pass
|
||||
|
||||
|
||||
def get_python_version():
|
||||
"""Return a string containing the major and minor Python version,
|
||||
leaving off the patchlevel. Sample return values could be '1.5'
|
||||
|
|
@ -99,7 +105,7 @@ def get_python_inc(plat_specific=0, prefix=None):
|
|||
"""
|
||||
if prefix is None:
|
||||
prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
|
||||
if 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:
|
||||
|
|
@ -115,18 +121,21 @@ def get_python_inc(plat_specific=0, prefix=None):
|
|||
return os.path.normpath(incdir)
|
||||
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":
|
||||
return os.path.join(prefix, 'include', python_dir)
|
||||
elif os.name == 'nt':
|
||||
if python_build:
|
||||
# Include both the include and PC dir to ensure we can find
|
||||
# pyconfig.h
|
||||
return (os.path.join(prefix, "include") + os.path.pathsep +
|
||||
os.path.join(prefix, "PC"))
|
||||
return os.path.join(prefix, "include")
|
||||
return (
|
||||
os.path.join(prefix, 'include') + os.path.pathsep +
|
||||
os.path.join(prefix, 'PC')
|
||||
)
|
||||
return os.path.join(prefix, 'include')
|
||||
else:
|
||||
raise DistutilsPlatformError(
|
||||
"I don't know where Python installs its C header files "
|
||||
"on platform '%s'" % os.name)
|
||||
"on platform '%s'" % os.name,
|
||||
)
|
||||
|
||||
|
||||
def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
|
||||
|
|
@ -149,7 +158,7 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
|
|||
if prefix is None:
|
||||
prefix = PREFIX
|
||||
if standard_lib:
|
||||
return os.path.join(prefix, "lib-python", sys.version[0])
|
||||
return os.path.join(prefix, 'lib-python', sys.version[0])
|
||||
return os.path.join(prefix, 'site-packages')
|
||||
|
||||
if prefix is None:
|
||||
|
|
@ -158,31 +167,33 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
|
|||
else:
|
||||
prefix = plat_specific and EXEC_PREFIX or PREFIX
|
||||
|
||||
if os.name == "posix":
|
||||
if os.name == 'posix':
|
||||
if plat_specific or standard_lib:
|
||||
# Platform-specific modules (any module from a non-pure-Python
|
||||
# module distribution) or standard Python library modules.
|
||||
libdir = getattr(sys, "platlibdir", "lib")
|
||||
libdir = getattr(sys, 'platlibdir', 'lib')
|
||||
else:
|
||||
# Pure Python
|
||||
libdir = "lib"
|
||||
libdir = 'lib'
|
||||
implementation = 'pypy' if IS_PYPY else 'python'
|
||||
libpython = os.path.join(prefix, libdir,
|
||||
implementation + get_python_version())
|
||||
libpython = os.path.join(
|
||||
prefix, libdir,
|
||||
implementation + get_python_version(),
|
||||
)
|
||||
if standard_lib:
|
||||
return libpython
|
||||
else:
|
||||
return os.path.join(libpython, "site-packages")
|
||||
elif os.name == "nt":
|
||||
return os.path.join(libpython, 'site-packages')
|
||||
elif os.name == 'nt':
|
||||
if standard_lib:
|
||||
return os.path.join(prefix, "Lib")
|
||||
return os.path.join(prefix, 'Lib')
|
||||
else:
|
||||
return os.path.join(prefix, "Lib", "site-packages")
|
||||
return os.path.join(prefix, 'Lib', 'site-packages')
|
||||
else:
|
||||
raise DistutilsPlatformError(
|
||||
"I don't know where Python installs its library "
|
||||
"on platform '%s'" % os.name)
|
||||
|
||||
"on platform '%s'" % os.name,
|
||||
)
|
||||
|
||||
|
||||
def customize_compiler(compiler):
|
||||
|
|
@ -191,8 +202,8 @@ def customize_compiler(compiler):
|
|||
Mainly needed on Unix, so we can plug in the information that
|
||||
varies across Unices and is stored in Python's Makefile.
|
||||
"""
|
||||
if compiler.compiler_type == "unix":
|
||||
if sys.platform == "darwin":
|
||||
if compiler.compiler_type == 'unix':
|
||||
if sys.platform == 'darwin':
|
||||
# Perform first-time customization of compiler-related
|
||||
# config vars on OS X now that we know we need a compiler.
|
||||
# This is primarily to support Pythons from binary
|
||||
|
|
@ -209,13 +220,17 @@ def customize_compiler(compiler):
|
|||
_config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
|
||||
|
||||
(cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
|
||||
get_config_vars('CC', 'CXX', 'CFLAGS',
|
||||
'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
|
||||
get_config_vars(
|
||||
'CC', 'CXX', 'CFLAGS',
|
||||
'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS',
|
||||
)
|
||||
|
||||
if 'CC' in os.environ:
|
||||
newcc = os.environ['CC']
|
||||
if('LDSHARED' not in os.environ
|
||||
and ldshared.startswith(cc)):
|
||||
if (
|
||||
'LDSHARED' not in os.environ and
|
||||
ldshared.startswith(cc)
|
||||
):
|
||||
# If CC is overridden, use that as the default
|
||||
# command for LDSHARED as well
|
||||
ldshared = newcc + ldshared[len(cc):]
|
||||
|
|
@ -227,7 +242,7 @@ def customize_compiler(compiler):
|
|||
if 'CPP' in os.environ:
|
||||
cpp = os.environ['CPP']
|
||||
else:
|
||||
cpp = cc + " -E" # not always
|
||||
cpp = cc + ' -E' # not always
|
||||
if 'LDFLAGS' in os.environ:
|
||||
ldshared = ldshared + ' ' + os.environ['LDFLAGS']
|
||||
if 'CFLAGS' in os.environ:
|
||||
|
|
@ -252,7 +267,8 @@ def customize_compiler(compiler):
|
|||
compiler_cxx=cxx,
|
||||
linker_so=ldshared,
|
||||
linker_exe=cc,
|
||||
archiver=archiver)
|
||||
archiver=archiver,
|
||||
)
|
||||
|
||||
if 'RANLIB' in os.environ and compiler.executables.get('ranlib', None):
|
||||
compiler.set_executables(ranlib=os.environ['RANLIB'])
|
||||
|
|
@ -263,8 +279,8 @@ def customize_compiler(compiler):
|
|||
def get_config_h_filename():
|
||||
"""Return full pathname of installed pyconfig.h file."""
|
||||
if python_build:
|
||||
if os.name == "nt":
|
||||
inc_dir = os.path.join(_sys_home or project_base, "PC")
|
||||
if os.name == 'nt':
|
||||
inc_dir = os.path.join(_sys_home or project_base, 'PC')
|
||||
else:
|
||||
inc_dir = _sys_home or project_base
|
||||
else:
|
||||
|
|
@ -276,9 +292,9 @@ def get_config_h_filename():
|
|||
def get_makefile_filename():
|
||||
"""Return full pathname of installed Makefile from the Python build."""
|
||||
if python_build:
|
||||
return os.path.join(_sys_home or project_base, "Makefile")
|
||||
return os.path.join(_sys_home or project_base, 'Makefile')
|
||||
lib_dir = get_python_lib(plat_specific=0, standard_lib=1)
|
||||
config_file = 'config-{}{}'.format(get_python_version(), build_flags)
|
||||
config_file = f'config-{get_python_version()}{build_flags}'
|
||||
if hasattr(sys.implementation, '_multiarch'):
|
||||
config_file += '-%s' % sys.implementation._multiarch
|
||||
return os.path.join(lib_dir, config_file, 'Makefile')
|
||||
|
|
@ -293,8 +309,8 @@ def parse_config_h(fp, g=None):
|
|||
"""
|
||||
if g is None:
|
||||
g = {}
|
||||
define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
|
||||
undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
|
||||
define_rx = re.compile('#define ([A-Z][A-Za-z0-9_]+) (.*)\n')
|
||||
undef_rx = re.compile('/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n')
|
||||
#
|
||||
while True:
|
||||
line = fp.readline()
|
||||
|
|
@ -303,8 +319,10 @@ def parse_config_h(fp, g=None):
|
|||
m = define_rx.match(line)
|
||||
if m:
|
||||
n, v = m.group(1, 2)
|
||||
try: v = int(v)
|
||||
except ValueError: pass
|
||||
try:
|
||||
v = int(v)
|
||||
except ValueError:
|
||||
pass
|
||||
g[n] = v
|
||||
else:
|
||||
m = undef_rx.match(line)
|
||||
|
|
@ -315,9 +333,10 @@ def parse_config_h(fp, g=None):
|
|||
|
||||
# Regexes needed for parsing Makefile (and similar syntaxes,
|
||||
# like old-style Setup files).
|
||||
_variable_rx = re.compile(r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)")
|
||||
_findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
|
||||
_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
|
||||
_variable_rx = re.compile(r'([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)')
|
||||
_findvar1_rx = re.compile(r'\$\(([A-Za-z][A-Za-z0-9_]*)\)')
|
||||
_findvar2_rx = re.compile(r'\${([A-Za-z][A-Za-z0-9_]*)}')
|
||||
|
||||
|
||||
def parse_makefile(fn, g=None):
|
||||
"""Parse a Makefile-style file.
|
||||
|
|
@ -327,7 +346,7 @@ def parse_makefile(fn, g=None):
|
|||
used instead of a new dictionary.
|
||||
"""
|
||||
from distutils.text_file import TextFile
|
||||
fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape")
|
||||
fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors='surrogateescape')
|
||||
|
||||
if g is None:
|
||||
g = {}
|
||||
|
|
@ -336,7 +355,7 @@ def parse_makefile(fn, g=None):
|
|||
|
||||
while True:
|
||||
line = fp.readline()
|
||||
if line is None: # eof
|
||||
if line is None: # eof
|
||||
break
|
||||
m = _variable_rx.match(line)
|
||||
if m:
|
||||
|
|
@ -345,7 +364,7 @@ def parse_makefile(fn, g=None):
|
|||
# `$$' is a literal `$' in make
|
||||
tmpv = v.replace('$$', '')
|
||||
|
||||
if "$" in tmpv:
|
||||
if '$' in tmpv:
|
||||
notdone[n] = v
|
||||
else:
|
||||
try:
|
||||
|
|
@ -381,7 +400,7 @@ def parse_makefile(fn, g=None):
|
|||
|
||||
elif n in renamed_variables:
|
||||
if name.startswith('PY_') and name[3:] in renamed_variables:
|
||||
item = ""
|
||||
item = ''
|
||||
|
||||
elif 'PY_' + n in notdone:
|
||||
found = False
|
||||
|
|
@ -389,14 +408,15 @@ def parse_makefile(fn, g=None):
|
|||
else:
|
||||
item = str(done['PY_' + n])
|
||||
else:
|
||||
done[n] = item = ""
|
||||
done[n] = item = ''
|
||||
if found:
|
||||
after = value[m.end():]
|
||||
value = value[:m.start()] + item + after
|
||||
if "$" in after:
|
||||
if '$' in after:
|
||||
notdone[name] = value
|
||||
else:
|
||||
try: value = int(value)
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
done[name] = value.strip()
|
||||
else:
|
||||
|
|
@ -404,7 +424,7 @@ def parse_makefile(fn, g=None):
|
|||
del notdone[name]
|
||||
|
||||
if name.startswith('PY_') \
|
||||
and name[3:] in renamed_variables:
|
||||
and name[3:] in renamed_variables:
|
||||
|
||||
name = name[3:]
|
||||
if name not in done:
|
||||
|
|
@ -452,21 +472,25 @@ def expand_makefile_vars(s, vars):
|
|||
|
||||
_config_vars = None
|
||||
|
||||
|
||||
def _init_posix():
|
||||
"""Initialize the module as appropriate for POSIX systems."""
|
||||
# _sysconfigdata is generated at build time, see the sysconfig module
|
||||
name = os.environ.get('_PYTHON_SYSCONFIGDATA_NAME',
|
||||
name = os.environ.get(
|
||||
'_PYTHON_SYSCONFIGDATA_NAME',
|
||||
'_sysconfigdata_{abi}_{platform}_{multiarch}'.format(
|
||||
abi=sys.abiflags,
|
||||
platform=sys.platform,
|
||||
multiarch=getattr(sys.implementation, '_multiarch', ''),
|
||||
))
|
||||
abi=sys.abiflags,
|
||||
platform=sys.platform,
|
||||
multiarch=getattr(sys.implementation, '_multiarch', ''),
|
||||
),
|
||||
)
|
||||
try:
|
||||
_temp = __import__(name, globals(), locals(), ['build_time_vars'], 0)
|
||||
except ImportError:
|
||||
# Python 3.5 and pypy 7.3.1
|
||||
_temp = __import__(
|
||||
'_sysconfigdata', globals(), locals(), ['build_time_vars'], 0)
|
||||
'_sysconfigdata', globals(), locals(), ['build_time_vars'], 0,
|
||||
)
|
||||
build_time_vars = _temp.build_time_vars
|
||||
global _config_vars
|
||||
_config_vars = {}
|
||||
|
|
@ -484,8 +508,8 @@ def _init_nt():
|
|||
g['INCLUDEPY'] = get_python_inc(plat_specific=0)
|
||||
|
||||
g['EXT_SUFFIX'] = _imp.extension_suffixes()[0]
|
||||
g['EXE'] = ".exe"
|
||||
g['VERSION'] = get_python_version().replace(".", "")
|
||||
g['EXE'] = '.exe'
|
||||
g['VERSION'] = get_python_version().replace('.', '')
|
||||
g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable))
|
||||
|
||||
global _config_vars
|
||||
|
|
@ -504,7 +528,7 @@ def get_config_vars(*args):
|
|||
"""
|
||||
global _config_vars
|
||||
if _config_vars is None:
|
||||
func = globals().get("_init_" + os.name)
|
||||
func = globals().get('_init_' + os.name)
|
||||
if func:
|
||||
func()
|
||||
else:
|
||||
|
|
@ -543,10 +567,12 @@ def get_config_vars(*args):
|
|||
# Normally it is relative to the build directory. However, during
|
||||
# testing, for example, we might be running a non-installed python
|
||||
# from a different directory.
|
||||
if python_build and os.name == "posix":
|
||||
if python_build and os.name == 'posix':
|
||||
base = project_base
|
||||
if (not os.path.isabs(_config_vars['srcdir']) and
|
||||
base != os.getcwd()):
|
||||
if (
|
||||
not os.path.isabs(_config_vars['srcdir']) and
|
||||
base != os.getcwd()
|
||||
):
|
||||
# srcdir is relative and we are not in the same directory
|
||||
# as the executable. Assume executable is in the build
|
||||
# directory and make srcdir absolute.
|
||||
|
|
@ -567,6 +593,7 @@ def get_config_vars(*args):
|
|||
else:
|
||||
return _config_vars
|
||||
|
||||
|
||||
def get_config_var(name):
|
||||
"""Return the value of a single variable using the dictionary
|
||||
returned by 'get_config_vars()'. Equivalent to
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
provides the TextFile class, which gives an interface to text files
|
||||
that (optionally) takes care of stripping comments, ignoring blank
|
||||
lines, and joining lines with backslashes."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys, io
|
||||
import io
|
||||
import sys
|
||||
|
||||
|
||||
class TextFile:
|
||||
|
|
@ -66,14 +68,14 @@ class TextFile:
|
|||
an all-whitespace line), if 'rstrip_ws' is true but 'skip_blanks' is
|
||||
not."""
|
||||
|
||||
default_options = { 'strip_comments': 1,
|
||||
'skip_blanks': 1,
|
||||
'lstrip_ws': 0,
|
||||
'rstrip_ws': 1,
|
||||
'join_lines': 0,
|
||||
'collapse_join': 0,
|
||||
'errors': 'strict',
|
||||
}
|
||||
default_options = {'strip_comments': 1,
|
||||
'skip_blanks': 1,
|
||||
'lstrip_ws': 0,
|
||||
'rstrip_ws': 1,
|
||||
'join_lines': 0,
|
||||
'collapse_join': 0,
|
||||
'errors': 'strict',
|
||||
}
|
||||
|
||||
def __init__(self, filename=None, file=None, **options):
|
||||
"""Construct a new TextFile object. At least one of 'filename'
|
||||
|
|
@ -112,7 +114,7 @@ class TextFile:
|
|||
"""Open a new file named 'filename'. This overrides both the
|
||||
'filename' and 'file' arguments to the constructor."""
|
||||
self.filename = filename
|
||||
self.file = io.open(self.filename, 'r', errors=self.errors)
|
||||
self.file = open(self.filename, errors=self.errors)
|
||||
self.current_line = 0
|
||||
|
||||
def close(self):
|
||||
|
|
@ -128,16 +130,16 @@ class TextFile:
|
|||
outmsg = []
|
||||
if line is None:
|
||||
line = self.current_line
|
||||
outmsg.append(self.filename + ", ")
|
||||
outmsg.append(self.filename + ', ')
|
||||
if isinstance(line, (list, tuple)):
|
||||
outmsg.append("lines %d-%d: " % tuple(line))
|
||||
outmsg.append('lines %d-%d: ' % tuple(line))
|
||||
else:
|
||||
outmsg.append("line %d: " % line)
|
||||
outmsg.append('line %d: ' % line)
|
||||
outmsg.append(str(msg))
|
||||
return "".join(outmsg)
|
||||
return ''.join(outmsg)
|
||||
|
||||
def error(self, msg, line=None):
|
||||
raise ValueError("error: " + self.gen_error(msg, line))
|
||||
raise ValueError('error: ' + self.gen_error(msg, line))
|
||||
|
||||
def warn(self, msg, line=None):
|
||||
"""Print (to stderr) a warning message tied to the current logical
|
||||
|
|
@ -147,7 +149,7 @@ class TextFile:
|
|||
the current line number; it may be a list or tuple to indicate a
|
||||
range of physical lines, or an integer for a single physical
|
||||
line."""
|
||||
sys.stderr.write("warning: " + self.gen_error(msg, line) + "\n")
|
||||
sys.stderr.write('warning: ' + self.gen_error(msg, line) + '\n')
|
||||
|
||||
def readline(self):
|
||||
"""Read and return a single logical line from the current file (or
|
||||
|
|
@ -186,13 +188,13 @@ class TextFile:
|
|||
# unescape it (and any other escaped "#"'s that might be
|
||||
# lurking in there) and otherwise leave the line alone.
|
||||
|
||||
pos = line.find("#")
|
||||
if pos == -1: # no "#" -- no comments
|
||||
pos = line.find('#')
|
||||
if pos == -1: # no "#" -- no comments
|
||||
pass
|
||||
|
||||
# It's definitely a comment -- either "#" is the first
|
||||
# character, or it's elsewhere and unescaped.
|
||||
elif pos == 0 or line[pos-1] != "\\":
|
||||
elif pos == 0 or line[pos - 1] != '\\':
|
||||
# Have to preserve the trailing newline, because it's
|
||||
# the job of a later step (rstrip_ws) to remove it --
|
||||
# and if rstrip_ws is false, we'd better preserve it!
|
||||
|
|
@ -209,17 +211,19 @@ class TextFile:
|
|||
# # comment that should be ignored
|
||||
# there
|
||||
# result in "hello there".
|
||||
if line.strip() == "":
|
||||
if line.strip() == '':
|
||||
continue
|
||||
else: # it's an escaped "#"
|
||||
line = line.replace("\\#", "#")
|
||||
else: # it's an escaped "#"
|
||||
line = line.replace('\\#', '#')
|
||||
|
||||
# did previous line end with a backslash? then accumulate
|
||||
if self.join_lines and buildup_line:
|
||||
# oops: end of file
|
||||
if line is None:
|
||||
self.warn("continuation line immediately precedes "
|
||||
"end-of-file")
|
||||
self.warn(
|
||||
'continuation line immediately precedes '
|
||||
'end-of-file',
|
||||
)
|
||||
return buildup_line
|
||||
|
||||
if self.collapse_join:
|
||||
|
|
@ -230,11 +234,13 @@ class TextFile:
|
|||
if isinstance(self.current_line, list):
|
||||
self.current_line[1] = self.current_line[1] + 1
|
||||
else:
|
||||
self.current_line = [self.current_line,
|
||||
self.current_line + 1]
|
||||
self.current_line = [
|
||||
self.current_line,
|
||||
self.current_line + 1,
|
||||
]
|
||||
# just an ordinary line, read it as usual
|
||||
else:
|
||||
if line is None: # eof
|
||||
if line is None: # eof
|
||||
return None
|
||||
|
||||
# still have to be careful about incrementing the line number!
|
||||
|
|
|
|||
|
|
@ -12,16 +12,23 @@ the "typical" Unix-style command-line C compiler:
|
|||
* link static library handled by 'ar' command (possibly with 'ranlib')
|
||||
* link shared library handled by 'cc -shared'
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os, sys, re, shlex
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
from distutils import sysconfig
|
||||
from distutils.dep_util import newer
|
||||
from distutils.ccompiler import \
|
||||
CCompiler, gen_preprocess_options, gen_lib_options
|
||||
from distutils.errors import \
|
||||
DistutilsExecError, CompileError, LibError, LinkError
|
||||
from distutils import log
|
||||
from distutils import sysconfig
|
||||
from distutils.ccompiler import CCompiler
|
||||
from distutils.ccompiler import gen_lib_options
|
||||
from distutils.ccompiler import gen_preprocess_options
|
||||
from distutils.dep_util import newer
|
||||
from distutils.errors import CompileError
|
||||
from distutils.errors import DistutilsExecError
|
||||
from distutils.errors import LibError
|
||||
from distutils.errors import LinkError
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
import _osx_support
|
||||
|
|
@ -52,18 +59,19 @@ class UnixCCompiler(CCompiler):
|
|||
# are pretty generic; they will probably have to be set by an outsider
|
||||
# (eg. using information discovered by the sysconfig about building
|
||||
# Python extensions).
|
||||
executables = {'preprocessor' : None,
|
||||
'compiler' : ["cc"],
|
||||
'compiler_so' : ["cc"],
|
||||
'compiler_cxx' : ["cc"],
|
||||
'linker_so' : ["cc", "-shared"],
|
||||
'linker_exe' : ["cc"],
|
||||
'archiver' : ["ar", "-cr"],
|
||||
'ranlib' : None,
|
||||
}
|
||||
executables = {
|
||||
'preprocessor': None,
|
||||
'compiler': ['cc'],
|
||||
'compiler_so': ['cc'],
|
||||
'compiler_cxx': ['cc'],
|
||||
'linker_so': ['cc', '-shared'],
|
||||
'linker_exe': ['cc'],
|
||||
'archiver': ['ar', '-cr'],
|
||||
'ranlib': None,
|
||||
}
|
||||
|
||||
if sys.platform[:6] == "darwin":
|
||||
executables['ranlib'] = ["ranlib"]
|
||||
if sys.platform[:6] == 'darwin':
|
||||
executables['ranlib'] = ['ranlib']
|
||||
|
||||
# Needed for the filename generation methods provided by the base
|
||||
# class, CCompiler. NB. whoever instantiates/uses a particular
|
||||
|
|
@ -71,19 +79,21 @@ class UnixCCompiler(CCompiler):
|
|||
# reasonable common default here, but it's not necessarily used on all
|
||||
# Unices!
|
||||
|
||||
src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"]
|
||||
obj_extension = ".o"
|
||||
static_lib_extension = ".a"
|
||||
shared_lib_extension = ".so"
|
||||
dylib_lib_extension = ".dylib"
|
||||
xcode_stub_lib_extension = ".tbd"
|
||||
static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s"
|
||||
src_extensions = ['.c', '.C', '.cc', '.cxx', '.cpp', '.m']
|
||||
obj_extension = '.o'
|
||||
static_lib_extension = '.a'
|
||||
shared_lib_extension = '.so'
|
||||
dylib_lib_extension = '.dylib'
|
||||
xcode_stub_lib_extension = '.tbd'
|
||||
static_lib_format = shared_lib_format = dylib_lib_format = 'lib%s%s'
|
||||
xcode_stub_lib_format = dylib_lib_format
|
||||
if sys.platform == "cygwin":
|
||||
exe_extension = ".exe"
|
||||
if sys.platform == 'cygwin':
|
||||
exe_extension = '.exe'
|
||||
|
||||
def preprocess(self, source, output_file=None, macros=None,
|
||||
include_dirs=None, extra_preargs=None, extra_postargs=None):
|
||||
def preprocess(
|
||||
self, source, output_file=None, macros=None,
|
||||
include_dirs=None, extra_preargs=None, extra_postargs=None,
|
||||
):
|
||||
fixed_args = self._fix_compile_args(None, macros, include_dirs)
|
||||
ignore, macros, include_dirs = fixed_args
|
||||
pp_opts = gen_preprocess_options(macros, include_dirs)
|
||||
|
|
@ -111,16 +121,22 @@ class UnixCCompiler(CCompiler):
|
|||
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
|
||||
compiler_so = self.compiler_so
|
||||
if sys.platform == 'darwin':
|
||||
compiler_so = _osx_support.compiler_fixup(compiler_so,
|
||||
cc_args + extra_postargs)
|
||||
compiler_so = _osx_support.compiler_fixup(
|
||||
compiler_so,
|
||||
cc_args + extra_postargs,
|
||||
)
|
||||
try:
|
||||
self.spawn(compiler_so + cc_args + [src, '-o', obj] +
|
||||
extra_postargs)
|
||||
self.spawn(
|
||||
compiler_so + cc_args + [src, '-o', obj] +
|
||||
extra_postargs,
|
||||
)
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
|
||||
def create_static_lib(self, objects, output_libname,
|
||||
output_dir=None, debug=0, target_lang=None):
|
||||
def create_static_lib(
|
||||
self, objects, output_libname,
|
||||
output_dir=None, debug=0, target_lang=None,
|
||||
):
|
||||
objects, output_dir = self._fix_object_args(objects, output_dir)
|
||||
|
||||
output_filename = \
|
||||
|
|
@ -128,9 +144,11 @@ class UnixCCompiler(CCompiler):
|
|||
|
||||
if self._need_link(objects, output_filename):
|
||||
self.mkpath(os.path.dirname(output_filename))
|
||||
self.spawn(self.archiver +
|
||||
[output_filename] +
|
||||
objects + self.objects)
|
||||
self.spawn(
|
||||
self.archiver +
|
||||
[output_filename] +
|
||||
objects + self.objects,
|
||||
)
|
||||
|
||||
# Not many Unices required ranlib anymore -- SunOS 4.x is, I
|
||||
# think the only major Unix that does. Maybe we need some
|
||||
|
|
@ -143,28 +161,36 @@ class UnixCCompiler(CCompiler):
|
|||
except DistutilsExecError as msg:
|
||||
raise LibError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
def link(self, target_desc, objects,
|
||||
output_filename, output_dir=None, libraries=None,
|
||||
library_dirs=None, runtime_library_dirs=None,
|
||||
export_symbols=None, debug=0, extra_preargs=None,
|
||||
extra_postargs=None, build_temp=None, target_lang=None):
|
||||
def link(
|
||||
self, target_desc, objects,
|
||||
output_filename, output_dir=None, libraries=None,
|
||||
library_dirs=None, runtime_library_dirs=None,
|
||||
export_symbols=None, debug=0, extra_preargs=None,
|
||||
extra_postargs=None, build_temp=None, target_lang=None,
|
||||
):
|
||||
objects, output_dir = self._fix_object_args(objects, output_dir)
|
||||
fixed_args = self._fix_lib_args(libraries, library_dirs,
|
||||
runtime_library_dirs)
|
||||
fixed_args = self._fix_lib_args(
|
||||
libraries, library_dirs,
|
||||
runtime_library_dirs,
|
||||
)
|
||||
libraries, library_dirs, runtime_library_dirs = fixed_args
|
||||
|
||||
lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs,
|
||||
libraries)
|
||||
lib_opts = gen_lib_options(
|
||||
self, library_dirs, runtime_library_dirs,
|
||||
libraries,
|
||||
)
|
||||
if not isinstance(output_dir, (str, type(None))):
|
||||
raise TypeError("'output_dir' must be a string or None")
|
||||
if output_dir is not None:
|
||||
output_filename = os.path.join(output_dir, output_filename)
|
||||
|
||||
if self._need_link(objects, output_filename):
|
||||
ld_args = (objects + self.objects +
|
||||
lib_opts + ['-o', output_filename])
|
||||
ld_args = (
|
||||
objects + self.objects +
|
||||
lib_opts + ['-o', output_filename]
|
||||
)
|
||||
if debug:
|
||||
ld_args[:0] = ['-g']
|
||||
if extra_preargs:
|
||||
|
|
@ -177,14 +203,14 @@ class UnixCCompiler(CCompiler):
|
|||
linker = self.linker_exe[:]
|
||||
else:
|
||||
linker = self.linker_so[:]
|
||||
if target_lang == "c++" and self.compiler_cxx:
|
||||
if target_lang == 'c++' and self.compiler_cxx:
|
||||
# skip over environment variable settings if /usr/bin/env
|
||||
# is used to set up the linker's environment.
|
||||
# This is needed on OSX. Note: this assumes that the
|
||||
# normal and C++ compiler have the same environment
|
||||
# settings.
|
||||
i = 0
|
||||
if os.path.basename(linker[0]) == "env":
|
||||
if os.path.basename(linker[0]) == 'env':
|
||||
i = 1
|
||||
while '=' in linker[i]:
|
||||
i += 1
|
||||
|
|
@ -196,7 +222,7 @@ class UnixCCompiler(CCompiler):
|
|||
else:
|
||||
offset = 0
|
||||
|
||||
linker[i+offset] = self.compiler_cxx[i]
|
||||
linker[i + offset] = self.compiler_cxx[i]
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
linker = _osx_support.compiler_fixup(linker, ld_args)
|
||||
|
|
@ -205,17 +231,17 @@ class UnixCCompiler(CCompiler):
|
|||
except DistutilsExecError as msg:
|
||||
raise LinkError(msg)
|
||||
else:
|
||||
log.debug("skipping %s (up-to-date)", output_filename)
|
||||
log.debug('skipping %s (up-to-date)', output_filename)
|
||||
|
||||
# -- Miscellaneous methods -----------------------------------------
|
||||
# These are all used by the 'gen_lib_options() function, in
|
||||
# ccompiler.py.
|
||||
|
||||
def library_dir_option(self, dir):
|
||||
return "-L" + dir
|
||||
return '-L' + dir
|
||||
|
||||
def _is_gcc(self, compiler_name):
|
||||
return "gcc" in compiler_name or "g++" in compiler_name
|
||||
return 'gcc' in compiler_name or 'g++' in compiler_name
|
||||
|
||||
def runtime_library_dir_option(self, dir):
|
||||
# XXX Hackish, at the very least. See Python bug #445902:
|
||||
|
|
@ -231,40 +257,40 @@ 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(shlex.split(sysconfig.get_config_var("CC"))[0])
|
||||
if sys.platform[:6] == "darwin":
|
||||
compiler = os.path.basename(shlex.split(sysconfig.get_config_var('CC'))[0])
|
||||
if sys.platform[:6] == 'darwin':
|
||||
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":
|
||||
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]
|
||||
return ['-Wl,+s', '-L' + dir]
|
||||
return ['+s', '-L' + 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":
|
||||
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
|
||||
return '-Wl,--enable-new-dtags,-R' + dir
|
||||
else:
|
||||
return "-Wl,-R" + dir
|
||||
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 '-R' + dir
|
||||
|
||||
def library_option(self, lib):
|
||||
return "-l" + lib
|
||||
return '-l' + lib
|
||||
|
||||
def find_library_file(self, dirs, lib, debug=0):
|
||||
shared_f = self.library_filename(lib, lib_type='shared')
|
||||
|
|
@ -298,8 +324,6 @@ class UnixCCompiler(CCompiler):
|
|||
else:
|
||||
sysroot = m.group(1)
|
||||
|
||||
|
||||
|
||||
for dir in dirs:
|
||||
shared = os.path.join(dir, shared_f)
|
||||
dylib = os.path.join(dir, dylib_f)
|
||||
|
|
@ -308,7 +332,9 @@ class UnixCCompiler(CCompiler):
|
|||
|
||||
if sys.platform == 'darwin' and (
|
||||
dir.startswith('/System/') or (
|
||||
dir.startswith('/usr/') and not dir.startswith('/usr/local/'))):
|
||||
dir.startswith('/usr/') and not dir.startswith('/usr/local/')
|
||||
)
|
||||
):
|
||||
|
||||
shared = os.path.join(sysroot, dir[1:], shared_f)
|
||||
dylib = os.path.join(sysroot, dir[1:], dylib_f)
|
||||
|
|
|
|||
|
|
@ -3,17 +3,20 @@
|
|||
Miscellaneous utility functions -- anything that doesn't fit into
|
||||
one of the other *util.py modules.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
import re
|
||||
import importlib.util
|
||||
import string
|
||||
import sys
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
from distutils.dep_util import newer
|
||||
from distutils.spawn import spawn
|
||||
|
||||
from distutils import log
|
||||
from distutils.dep_util import newer
|
||||
from distutils.errors import DistutilsByteCompileError
|
||||
from distutils.errors import DistutilsPlatformError
|
||||
from distutils.spawn import spawn
|
||||
|
||||
from .py35compat import _optim_args_from_interpreter_flags
|
||||
|
||||
|
||||
|
|
@ -47,10 +50,10 @@ def get_host_platform():
|
|||
return sys.platform
|
||||
|
||||
# Set for cross builds explicitly
|
||||
if "_PYTHON_HOST_PLATFORM" in os.environ:
|
||||
return os.environ["_PYTHON_HOST_PLATFORM"]
|
||||
if '_PYTHON_HOST_PLATFORM' in os.environ:
|
||||
return os.environ['_PYTHON_HOST_PLATFORM']
|
||||
|
||||
if os.name != "posix" or not hasattr(os, 'uname'):
|
||||
if os.name != 'posix' or not hasattr(os, 'uname'):
|
||||
# XXX what about the architecture? NT is Intel or Alpha,
|
||||
# Mac OS is M68k or PPC, etc.
|
||||
return sys.platform
|
||||
|
|
@ -65,44 +68,47 @@ def get_host_platform():
|
|||
machine = machine.replace(' ', '_')
|
||||
machine = machine.replace('/', '-')
|
||||
|
||||
if osname[:5] == "linux":
|
||||
if osname[:5] == 'linux':
|
||||
# At least on Linux/Intel, 'machine' is the processor --
|
||||
# i386, etc.
|
||||
# XXX what about Alpha, SPARC, etc?
|
||||
return "%s-%s" % (osname, machine)
|
||||
elif osname[:5] == "sunos":
|
||||
if release[0] >= "5": # SunOS 5 == Solaris 2
|
||||
osname = "solaris"
|
||||
release = "%d.%s" % (int(release[0]) - 3, release[2:])
|
||||
return '{}-{}'.format(osname, machine)
|
||||
elif osname[:5] == 'sunos':
|
||||
if release[0] >= '5': # SunOS 5 == Solaris 2
|
||||
osname = 'solaris'
|
||||
release = '%d.%s' % (int(release[0]) - 3, release[2:])
|
||||
# We can't use "platform.architecture()[0]" because a
|
||||
# bootstrap problem. We use a dict to get an error
|
||||
# if some suspicious happens.
|
||||
bitness = {2147483647:"32bit", 9223372036854775807:"64bit"}
|
||||
machine += ".%s" % bitness[sys.maxsize]
|
||||
bitness = {2147483647: '32bit', 9223372036854775807: '64bit'}
|
||||
machine += '.%s' % bitness[sys.maxsize]
|
||||
# fall through to standard osname-release-machine representation
|
||||
elif osname[:3] == "aix":
|
||||
elif osname[:3] == 'aix':
|
||||
from .py38compat import aix_platform
|
||||
return aix_platform(osname, version, release)
|
||||
elif osname[:6] == "cygwin":
|
||||
osname = "cygwin"
|
||||
rel_re = re.compile (r'[\d.]+', re.ASCII)
|
||||
elif osname[:6] == 'cygwin':
|
||||
osname = 'cygwin'
|
||||
rel_re = re.compile(r'[\d.]+', re.ASCII)
|
||||
m = rel_re.match(release)
|
||||
if m:
|
||||
release = m.group()
|
||||
elif osname[:6] == "darwin":
|
||||
import _osx_support, distutils.sysconfig
|
||||
elif osname[:6] == 'darwin':
|
||||
import _osx_support
|
||||
import distutils.sysconfig
|
||||
osname, release, machine = _osx_support.get_platform_osx(
|
||||
distutils.sysconfig.get_config_vars(),
|
||||
osname, release, machine)
|
||||
distutils.sysconfig.get_config_vars(),
|
||||
osname, release, machine,
|
||||
)
|
||||
|
||||
return '{}-{}-{}'.format(osname, release, machine)
|
||||
|
||||
return "%s-%s-%s" % (osname, release, machine)
|
||||
|
||||
def get_platform():
|
||||
if os.name == 'nt':
|
||||
TARGET_TO_PLAT = {
|
||||
'x86' : 'win32',
|
||||
'x64' : 'win-amd64',
|
||||
'arm' : 'win-arm32',
|
||||
'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()
|
||||
|
|
@ -111,14 +117,16 @@ def get_platform():
|
|||
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
_syscfg_macosx_ver = None # cache the version pulled from sysconfig
|
||||
_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."""
|
||||
|
|
@ -130,6 +138,7 @@ def get_macosx_target_ver_from_syscfg():
|
|||
_syscfg_macosx_ver = ver
|
||||
return _syscfg_macosx_ver
|
||||
|
||||
|
||||
def get_macosx_target_ver():
|
||||
"""Return the version of macOS for which we are building.
|
||||
|
||||
|
|
@ -148,11 +157,13 @@ def get_macosx_target_ver():
|
|||
# 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))
|
||||
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
|
||||
|
|
@ -163,7 +174,7 @@ def split_version(s):
|
|||
return [int(n) for n in s.split('.')]
|
||||
|
||||
|
||||
def convert_path (pathname):
|
||||
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
|
||||
directory separator. Needed because filenames in the setup script are
|
||||
|
|
@ -191,7 +202,7 @@ def convert_path (pathname):
|
|||
# convert_path ()
|
||||
|
||||
|
||||
def change_root (new_root, pathname):
|
||||
def change_root(new_root, pathname):
|
||||
"""Return 'pathname' with 'new_root' prepended. If 'pathname' is
|
||||
relative, this is equivalent to "os.path.join(new_root,pathname)".
|
||||
Otherwise, it requires making 'pathname' relative and then joining the
|
||||
|
|
@ -214,7 +225,9 @@ def change_root (new_root, pathname):
|
|||
|
||||
|
||||
_environ_checked = 0
|
||||
def check_environ ():
|
||||
|
||||
|
||||
def check_environ():
|
||||
"""Ensure that 'os.environ' has all the environment variables we
|
||||
guarantee that users can use in config files, command-line options,
|
||||
etc. Currently this includes:
|
||||
|
|
@ -241,7 +254,7 @@ def check_environ ():
|
|||
_environ_checked = 1
|
||||
|
||||
|
||||
def subst_vars (s, local_vars):
|
||||
def subst_vars(s, local_vars):
|
||||
"""Perform shell/Perl-style variable substitution on 'string'. Every
|
||||
occurrence of '$' followed by a name is considered a variable, and
|
||||
variable is substituted by the value found in the 'local_vars'
|
||||
|
|
@ -251,7 +264,8 @@ def subst_vars (s, local_vars):
|
|||
variables not found in either 'local_vars' or 'os.environ'.
|
||||
"""
|
||||
check_environ()
|
||||
def _subst (match, local_vars=local_vars):
|
||||
|
||||
def _subst(match, local_vars=local_vars):
|
||||
var_name = match.group(1)
|
||||
if var_name in local_vars:
|
||||
return str(local_vars[var_name])
|
||||
|
|
@ -266,7 +280,7 @@ def subst_vars (s, local_vars):
|
|||
# subst_vars ()
|
||||
|
||||
|
||||
def grok_environment_error (exc, prefix="error: "):
|
||||
def grok_environment_error(exc, prefix='error: '):
|
||||
# Function kept for backward compatibility.
|
||||
# Used to try clever things with EnvironmentErrors,
|
||||
# but nowadays str(exception) produces good messages.
|
||||
|
|
@ -275,13 +289,16 @@ def grok_environment_error (exc, prefix="error: "):
|
|||
|
||||
# Needed by 'split_quoted()'
|
||||
_wordchars_re = _squote_re = _dquote_re = None
|
||||
|
||||
|
||||
def _init_regex():
|
||||
global _wordchars_re, _squote_re, _dquote_re
|
||||
_wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace)
|
||||
_squote_re = re.compile(r"'(?:[^'\\]|\\.)*'")
|
||||
_dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"')
|
||||
|
||||
def split_quoted (s):
|
||||
|
||||
def split_quoted(s):
|
||||
"""Split a string up according to Unix shell-like rules for quotes and
|
||||
backslashes. In short: words are delimited by spaces, as long as those
|
||||
spaces are not escaped by a backslash, or inside a quoted string.
|
||||
|
|
@ -295,7 +312,8 @@ def split_quoted (s):
|
|||
# This is a nice algorithm for splitting up a single string, since it
|
||||
# doesn't require character-by-character examination. It was a little
|
||||
# bit of a brain-bender to get it working right, though...
|
||||
if _wordchars_re is None: _init_regex()
|
||||
if _wordchars_re is None:
|
||||
_init_regex()
|
||||
|
||||
s = s.strip()
|
||||
words = []
|
||||
|
|
@ -308,15 +326,15 @@ def split_quoted (s):
|
|||
words.append(s[:end])
|
||||
break
|
||||
|
||||
if s[end] in string.whitespace: # unescaped, unquoted whitespace: now
|
||||
if s[end] in string.whitespace: # unescaped, unquoted whitespace: now
|
||||
words.append(s[:end]) # we definitely have a word delimiter
|
||||
s = s[end:].lstrip()
|
||||
pos = 0
|
||||
|
||||
elif s[end] == '\\': # preserve whatever is being escaped;
|
||||
# will become part of the current word
|
||||
s = s[:end] + s[end+1:]
|
||||
pos = end+1
|
||||
# will become part of the current word
|
||||
s = s[:end] + s[end + 1:]
|
||||
pos = end + 1
|
||||
|
||||
else:
|
||||
if s[end] == "'": # slurp singly-quoted string
|
||||
|
|
@ -327,10 +345,10 @@ def split_quoted (s):
|
|||
raise RuntimeError("this can't happen (bad char '%c')" % s[end])
|
||||
|
||||
if m is None:
|
||||
raise ValueError("bad string (mismatched %s quotes?)" % s[end])
|
||||
raise ValueError('bad string (mismatched %s quotes?)' % s[end])
|
||||
|
||||
(beg, end) = m.span()
|
||||
s = s[:beg] + s[beg+1:end-1] + s[end:]
|
||||
s = s[:beg] + s[beg + 1:end - 1] + s[end:]
|
||||
pos = m.end() - 2
|
||||
|
||||
if pos >= len(s):
|
||||
|
|
@ -342,7 +360,7 @@ def split_quoted (s):
|
|||
# split_quoted ()
|
||||
|
||||
|
||||
def execute (func, args, msg=None, verbose=0, dry_run=0):
|
||||
def execute(func, args, msg=None, verbose=0, dry_run=0):
|
||||
"""Perform some action that affects the outside world (eg. by
|
||||
writing to the filesystem). Such actions are special because they
|
||||
are disabled by the 'dry_run' flag. This method takes care of all
|
||||
|
|
@ -352,7 +370,7 @@ def execute (func, args, msg=None, verbose=0, dry_run=0):
|
|||
print.
|
||||
"""
|
||||
if msg is None:
|
||||
msg = "%s%r" % (func.__name__, args)
|
||||
msg = '{}{!r}'.format(func.__name__, args)
|
||||
if msg[-2:] == ',)': # correct for singleton tuple
|
||||
msg = msg[0:-2] + ')'
|
||||
|
||||
|
|
@ -361,7 +379,7 @@ def execute (func, args, msg=None, verbose=0, dry_run=0):
|
|||
func(*args)
|
||||
|
||||
|
||||
def strtobool (val):
|
||||
def strtobool(val):
|
||||
"""Convert a string representation of truth to true (1) or false (0).
|
||||
|
||||
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
|
||||
|
|
@ -374,14 +392,16 @@ def strtobool (val):
|
|||
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
|
||||
return 0
|
||||
else:
|
||||
raise ValueError("invalid truth value %r" % (val,))
|
||||
raise ValueError('invalid truth value {!r}'.format(val))
|
||||
|
||||
|
||||
def byte_compile (py_files,
|
||||
optimize=0, force=0,
|
||||
prefix=None, base_dir=None,
|
||||
verbose=1, dry_run=0,
|
||||
direct=None):
|
||||
def byte_compile(
|
||||
py_files,
|
||||
optimize=0, force=0,
|
||||
prefix=None, base_dir=None,
|
||||
verbose=1, dry_run=0,
|
||||
direct=None,
|
||||
):
|
||||
"""Byte-compile a collection of Python source files to .pyc
|
||||
files in a __pycache__ subdirectory. 'py_files' is a list
|
||||
of files to compile; any files that don't end in ".py" are silently
|
||||
|
|
@ -437,16 +457,16 @@ def byte_compile (py_files,
|
|||
if not direct:
|
||||
try:
|
||||
from tempfile import mkstemp
|
||||
(script_fd, script_name) = mkstemp(".py")
|
||||
(script_fd, script_name) = mkstemp('.py')
|
||||
except ImportError:
|
||||
from tempfile import mktemp
|
||||
(script_fd, script_name) = None, mktemp(".py")
|
||||
(script_fd, script_name) = None, mktemp('.py')
|
||||
log.info("writing byte-compilation script '%s'", script_name)
|
||||
if not dry_run:
|
||||
if script_fd is not None:
|
||||
script = os.fdopen(script_fd, "w")
|
||||
script = os.fdopen(script_fd, 'w')
|
||||
else:
|
||||
script = open(script_name, "w")
|
||||
script = open(script_name, 'w')
|
||||
|
||||
with script:
|
||||
script.write("""\
|
||||
|
|
@ -468,20 +488,24 @@ files = [
|
|||
#if prefix:
|
||||
# prefix = os.path.abspath(prefix)
|
||||
|
||||
script.write(",\n".join(map(repr, py_files)) + "]\n")
|
||||
script.write("""
|
||||
byte_compile(files, optimize=%r, force=%r,
|
||||
prefix=%r, base_dir=%r,
|
||||
verbose=%r, dry_run=0,
|
||||
script.write(',\n'.join(map(repr, py_files)) + ']\n')
|
||||
script.write(
|
||||
"""
|
||||
byte_compile(files, optimize={!r}, force={!r},
|
||||
prefix={!r}, base_dir={!r},
|
||||
verbose={!r}, dry_run=0,
|
||||
direct=1)
|
||||
""" % (optimize, force, prefix, base_dir, verbose))
|
||||
""".format(optimize, force, prefix, base_dir, verbose),
|
||||
)
|
||||
|
||||
cmd = [sys.executable]
|
||||
cmd.extend(_optim_args_from_interpreter_flags())
|
||||
cmd.append(script_name)
|
||||
spawn(cmd, dry_run=dry_run)
|
||||
execute(os.remove, (script_name,), "removing %s" % script_name,
|
||||
dry_run=dry_run)
|
||||
execute(
|
||||
os.remove, (script_name,), 'removing %s' % script_name,
|
||||
dry_run=dry_run,
|
||||
)
|
||||
|
||||
# "Direct" byte-compilation: use the py_compile module to compile
|
||||
# right here, right now. Note that the script generated in indirect
|
||||
|
|
@ -491,7 +515,7 @@ byte_compile(files, optimize=%r, force=%r,
|
|||
from py_compile import compile
|
||||
|
||||
for file in py_files:
|
||||
if file[-3:] != ".py":
|
||||
if file[-3:] != '.py':
|
||||
# This lets us be lazy and not filter filenames in
|
||||
# the "install_lib" command.
|
||||
continue
|
||||
|
|
@ -502,14 +526,17 @@ byte_compile(files, optimize=%r, force=%r,
|
|||
if optimize >= 0:
|
||||
opt = '' if optimize == 0 else optimize
|
||||
cfile = importlib.util.cache_from_source(
|
||||
file, optimization=opt)
|
||||
file, optimization=opt,
|
||||
)
|
||||
else:
|
||||
cfile = importlib.util.cache_from_source(file)
|
||||
dfile = file
|
||||
if prefix:
|
||||
if file[:len(prefix)] != prefix:
|
||||
raise ValueError("invalid prefix: filename %r doesn't start with %r"
|
||||
% (file, prefix))
|
||||
raise ValueError(
|
||||
"invalid prefix: filename %r doesn't start with %r"
|
||||
% (file, prefix),
|
||||
)
|
||||
dfile = dfile[len(prefix):]
|
||||
if base_dir:
|
||||
dfile = os.path.join(base_dir, dfile)
|
||||
|
|
@ -517,16 +544,19 @@ byte_compile(files, optimize=%r, force=%r,
|
|||
cfile_base = os.path.basename(cfile)
|
||||
if direct:
|
||||
if force or newer(file, cfile):
|
||||
log.info("byte-compiling %s to %s", file, cfile_base)
|
||||
log.info('byte-compiling %s to %s', file, cfile_base)
|
||||
if not dry_run:
|
||||
compile(file, cfile, dfile)
|
||||
else:
|
||||
log.debug("skipping byte-compilation of %s to %s",
|
||||
file, cfile_base)
|
||||
log.debug(
|
||||
'skipping byte-compilation of %s to %s',
|
||||
file, cfile_base,
|
||||
)
|
||||
|
||||
# byte_compile ()
|
||||
|
||||
def rfc822_escape (header):
|
||||
|
||||
def rfc822_escape(header):
|
||||
"""Return a version of the string escaped for inclusion in an
|
||||
RFC-822 header, by ensuring there are 8 spaces space after each newline.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
"""Provides classes to represent module version numbers (one class for
|
||||
each style of version numbering). There are currently two such classes
|
||||
implemented: StrictVersion and LooseVersion.
|
||||
|
|
@ -25,9 +24,11 @@ Every version number class implements the following interface:
|
|||
of the same class or a string (which will be parsed to an instance
|
||||
of the same class, thus must follow the same rules)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class Version:
|
||||
"""Abstract base class for version numbering classes. Just provides
|
||||
constructor (__init__) and reproducer (__repr__), because those
|
||||
|
|
@ -35,12 +36,12 @@ class Version:
|
|||
rich comparisons to _cmp.
|
||||
"""
|
||||
|
||||
def __init__ (self, vstring=None):
|
||||
def __init__(self, vstring=None):
|
||||
if vstring:
|
||||
self.parse(vstring)
|
||||
|
||||
def __repr__ (self):
|
||||
return "%s ('%s')" % (self.__class__.__name__, str(self))
|
||||
def __repr__(self):
|
||||
return "{} ('{}')".format(self.__class__.__name__, str(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
c = self._cmp(other)
|
||||
|
|
@ -127,11 +128,12 @@ class StrictVersion (Version):
|
|||
in the distutils documentation.
|
||||
"""
|
||||
|
||||
version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',
|
||||
re.VERBOSE | re.ASCII)
|
||||
version_re = re.compile(
|
||||
r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',
|
||||
re.VERBOSE | re.ASCII,
|
||||
)
|
||||
|
||||
|
||||
def parse (self, vstring):
|
||||
def parse(self, vstring):
|
||||
match = self.version_re.match(vstring)
|
||||
if not match:
|
||||
raise ValueError("invalid version number '%s'" % vstring)
|
||||
|
|
@ -149,8 +151,7 @@ class StrictVersion (Version):
|
|||
else:
|
||||
self.prerelease = None
|
||||
|
||||
|
||||
def __str__ (self):
|
||||
def __str__(self):
|
||||
|
||||
if self.version[2] == 0:
|
||||
vstring = '.'.join(map(str, self.version[0:2]))
|
||||
|
|
@ -162,8 +163,7 @@ class StrictVersion (Version):
|
|||
|
||||
return vstring
|
||||
|
||||
|
||||
def _cmp (self, other):
|
||||
def _cmp(self, other):
|
||||
if isinstance(other, str):
|
||||
other = StrictVersion(other)
|
||||
elif not isinstance(other, StrictVersion):
|
||||
|
|
@ -197,7 +197,7 @@ class StrictVersion (Version):
|
|||
else:
|
||||
return 1
|
||||
else:
|
||||
assert False, "never get here"
|
||||
assert False, 'never get here'
|
||||
|
||||
# end class StrictVersion
|
||||
|
||||
|
|
@ -301,18 +301,19 @@ class LooseVersion (Version):
|
|||
|
||||
component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
|
||||
|
||||
def __init__ (self, vstring=None):
|
||||
def __init__(self, vstring=None):
|
||||
if vstring:
|
||||
self.parse(vstring)
|
||||
|
||||
|
||||
def parse (self, vstring):
|
||||
def parse(self, vstring):
|
||||
# I've given up on thinking I can reconstruct the version string
|
||||
# from the parsed tuple -- so I just store the string here for
|
||||
# use by __str__
|
||||
self.vstring = vstring
|
||||
components = [x for x in self.component_re.split(vstring)
|
||||
if x and x != '.']
|
||||
components = [
|
||||
x for x in self.component_re.split(vstring)
|
||||
if x and x != '.'
|
||||
]
|
||||
for i, obj in enumerate(components):
|
||||
try:
|
||||
components[i] = int(obj)
|
||||
|
|
@ -321,16 +322,13 @@ class LooseVersion (Version):
|
|||
|
||||
self.version = components
|
||||
|
||||
|
||||
def __str__ (self):
|
||||
def __str__(self):
|
||||
return self.vstring
|
||||
|
||||
|
||||
def __repr__ (self):
|
||||
def __repr__(self):
|
||||
return "LooseVersion ('%s')" % str(self)
|
||||
|
||||
|
||||
def _cmp (self, other):
|
||||
def _cmp(self, other):
|
||||
if isinstance(other, str):
|
||||
other = LooseVersion(other)
|
||||
elif not isinstance(other, LooseVersion):
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
"""Module for parsing and testing package version predicate strings.
|
||||
"""
|
||||
import re
|
||||
import distutils.version
|
||||
from __future__ import annotations
|
||||
|
||||
import operator
|
||||
import re
|
||||
|
||||
import distutils.version
|
||||
|
||||
|
||||
re_validPackage = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)",
|
||||
re.ASCII)
|
||||
re_validPackage = re.compile(
|
||||
r'(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)',
|
||||
re.ASCII,
|
||||
)
|
||||
# (package) (rest)
|
||||
|
||||
re_paren = re.compile(r"^\s*\((.*)\)\s*$") # (list) inside of parentheses
|
||||
re_splitComparison = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$")
|
||||
re_paren = re.compile(r'^\s*\((.*)\)\s*$') # (list) inside of parentheses
|
||||
re_splitComparison = re.compile(r'^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$')
|
||||
# (comp) (version)
|
||||
|
||||
|
||||
|
|
@ -21,12 +26,16 @@ def splitUp(pred):
|
|||
"""
|
||||
res = re_splitComparison.match(pred)
|
||||
if not res:
|
||||
raise ValueError("bad package restriction syntax: %r" % pred)
|
||||
raise ValueError('bad package restriction syntax: %r' % pred)
|
||||
comp, verStr = res.groups()
|
||||
return (comp, distutils.version.StrictVersion(verStr))
|
||||
|
||||
compmap = {"<": operator.lt, "<=": operator.le, "==": operator.eq,
|
||||
">": operator.gt, ">=": operator.ge, "!=": operator.ne}
|
||||
|
||||
compmap = {
|
||||
'<': operator.lt, '<=': operator.le, '==': operator.eq,
|
||||
'>': operator.gt, '>=': operator.ge, '!=': operator.ne,
|
||||
}
|
||||
|
||||
|
||||
class VersionPredicate:
|
||||
"""Parse and test package version predicates.
|
||||
|
|
@ -102,28 +111,30 @@ class VersionPredicate:
|
|||
|
||||
versionPredicateStr = versionPredicateStr.strip()
|
||||
if not versionPredicateStr:
|
||||
raise ValueError("empty package restriction")
|
||||
raise ValueError('empty package restriction')
|
||||
match = re_validPackage.match(versionPredicateStr)
|
||||
if not match:
|
||||
raise ValueError("bad package name in %r" % versionPredicateStr)
|
||||
raise ValueError('bad package name in %r' % versionPredicateStr)
|
||||
self.name, paren = match.groups()
|
||||
paren = paren.strip()
|
||||
if paren:
|
||||
match = re_paren.match(paren)
|
||||
if not match:
|
||||
raise ValueError("expected parenthesized list: %r" % paren)
|
||||
raise ValueError('expected parenthesized list: %r' % paren)
|
||||
str = match.groups()[0]
|
||||
self.pred = [splitUp(aPred) for aPred in str.split(",")]
|
||||
self.pred = [splitUp(aPred) for aPred in str.split(',')]
|
||||
if not self.pred:
|
||||
raise ValueError("empty parenthesized list in %r"
|
||||
% versionPredicateStr)
|
||||
raise ValueError(
|
||||
'empty parenthesized list in %r'
|
||||
% versionPredicateStr,
|
||||
)
|
||||
else:
|
||||
self.pred = []
|
||||
|
||||
def __str__(self):
|
||||
if self.pred:
|
||||
seq = [cond + " " + str(ver) for cond, ver in self.pred]
|
||||
return self.name + " (" + ", ".join(seq) + ")"
|
||||
seq = [cond + ' ' + str(ver) for cond, ver in self.pred]
|
||||
return self.name + ' (' + ', '.join(seq) + ')'
|
||||
else:
|
||||
return self.name
|
||||
|
||||
|
|
@ -140,6 +151,7 @@ class VersionPredicate:
|
|||
|
||||
_provision_rx = None
|
||||
|
||||
|
||||
def split_provision(value):
|
||||
"""Return the name and optional version number of a provision.
|
||||
|
||||
|
|
@ -154,12 +166,13 @@ def split_provision(value):
|
|||
global _provision_rx
|
||||
if _provision_rx is None:
|
||||
_provision_rx = re.compile(
|
||||
r"([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$",
|
||||
re.ASCII)
|
||||
r'([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)(?:\s*\(\s*([^)\s]+)\s*\))?$',
|
||||
re.ASCII,
|
||||
)
|
||||
value = value.strip()
|
||||
m = _provision_rx.match(value)
|
||||
if not m:
|
||||
raise ValueError("illegal provides specification: %r" % value)
|
||||
raise ValueError('illegal provides specification: %r' % value)
|
||||
ver = m.group(2) or None
|
||||
if ver:
|
||||
ver = distutils.version.StrictVersion(ver)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
Re-implementation of find_module and get_frozen_object
|
||||
from the deprecated imp module.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import importlib.util
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from .py34compat import module_from_spec
|
||||
|
||||
|
|
@ -38,12 +39,14 @@ def find_module(module, paths=None):
|
|||
file = None
|
||||
static = isinstance(spec.loader, type)
|
||||
if spec.origin == 'frozen' or static and issubclass(
|
||||
spec.loader, importlib.machinery.FrozenImporter):
|
||||
spec.loader, importlib.machinery.FrozenImporter,
|
||||
):
|
||||
kind = PY_FROZEN
|
||||
path = None # imp compabilty
|
||||
suffix = mode = '' # imp compatibility
|
||||
elif spec.origin == 'built-in' or static and issubclass(
|
||||
spec.loader, importlib.machinery.BuiltinImporter):
|
||||
spec.loader, importlib.machinery.BuiltinImporter,
|
||||
):
|
||||
kind = C_BUILTIN
|
||||
path = None # imp compabilty
|
||||
suffix = mode = '' # imp compatibility
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from .more import * # noqa
|
||||
from .recipes import * # noqa
|
||||
|
||||
|
|
|
|||
|
|
@ -1,39 +1,55 @@
|
|||
import warnings
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import Counter, defaultdict, deque, abc
|
||||
import warnings
|
||||
from collections import abc
|
||||
from collections import Counter
|
||||
from collections import defaultdict
|
||||
from collections import deque
|
||||
from collections.abc import Sequence
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from functools import partial, reduce, wraps
|
||||
from heapq import merge, heapify, heapreplace, heappop
|
||||
from itertools import (
|
||||
chain,
|
||||
compress,
|
||||
count,
|
||||
cycle,
|
||||
dropwhile,
|
||||
groupby,
|
||||
islice,
|
||||
repeat,
|
||||
starmap,
|
||||
takewhile,
|
||||
tee,
|
||||
zip_longest,
|
||||
)
|
||||
from math import exp, factorial, floor, log
|
||||
from queue import Empty, Queue
|
||||
from random import random, randrange, uniform
|
||||
from operator import itemgetter, mul, sub, gt, lt
|
||||
from sys import hexversion, maxsize
|
||||
from functools import partial
|
||||
from functools import reduce
|
||||
from functools import wraps
|
||||
from heapq import heapify
|
||||
from heapq import heappop
|
||||
from heapq import heapreplace
|
||||
from heapq import merge
|
||||
from itertools import chain
|
||||
from itertools import compress
|
||||
from itertools import count
|
||||
from itertools import cycle
|
||||
from itertools import dropwhile
|
||||
from itertools import groupby
|
||||
from itertools import islice
|
||||
from itertools import repeat
|
||||
from itertools import starmap
|
||||
from itertools import takewhile
|
||||
from itertools import tee
|
||||
from itertools import zip_longest
|
||||
from math import exp
|
||||
from math import factorial
|
||||
from math import floor
|
||||
from math import log
|
||||
from operator import gt
|
||||
from operator import itemgetter
|
||||
from operator import lt
|
||||
from operator import mul
|
||||
from operator import sub
|
||||
from queue import Empty
|
||||
from queue import Queue
|
||||
from random import random
|
||||
from random import randrange
|
||||
from random import uniform
|
||||
from sys import hexversion
|
||||
from sys import maxsize
|
||||
from time import monotonic
|
||||
|
||||
from .recipes import (
|
||||
consume,
|
||||
flatten,
|
||||
pairwise,
|
||||
powerset,
|
||||
take,
|
||||
unique_everseen,
|
||||
)
|
||||
from .recipes import consume
|
||||
from .recipes import flatten
|
||||
from .recipes import pairwise
|
||||
from .recipes import powerset
|
||||
from .recipes import take
|
||||
from .recipes import unique_everseen
|
||||
|
||||
__all__ = [
|
||||
'AbortThread',
|
||||
|
|
@ -180,7 +196,7 @@ def first(iterable, default=_marker):
|
|||
if default is _marker:
|
||||
raise ValueError(
|
||||
'first() was called on an empty iterable, and no '
|
||||
'default value was provided.'
|
||||
'default value was provided.',
|
||||
) from e
|
||||
return default
|
||||
|
||||
|
|
@ -209,7 +225,7 @@ def last(iterable, default=_marker):
|
|||
if default is _marker:
|
||||
raise ValueError(
|
||||
'last() was called on an empty iterable, and no default was '
|
||||
'provided.'
|
||||
'provided.',
|
||||
)
|
||||
return default
|
||||
|
||||
|
|
@ -428,7 +444,7 @@ def collate(*iterables, **kwargs):
|
|||
|
||||
"""
|
||||
warnings.warn(
|
||||
"collate is no longer part of more_itertools, use heapq.merge",
|
||||
'collate is no longer part of more_itertools, use heapq.merge',
|
||||
DeprecationWarning,
|
||||
)
|
||||
return merge(*iterables, **kwargs)
|
||||
|
|
@ -624,7 +640,7 @@ def distinct_permutations(iterable, r=None):
|
|||
# Swap the value of A[i] with that of A[j], then reverse the
|
||||
# sequence from A[i + 1] to form the new permutation
|
||||
A[i], A[j] = A[j], A[i]
|
||||
A[i + 1 :] = A[: i - size : -1] # A[i + 1:][::-1]
|
||||
A[i + 1:] = A[: i - size: -1] # A[i + 1:][::-1]
|
||||
|
||||
# Algorithm: modified from the above
|
||||
def _partial(A, r):
|
||||
|
|
@ -662,9 +678,9 @@ def distinct_permutations(iterable, r=None):
|
|||
break
|
||||
|
||||
# Reverse head[i + 1:] and swap it with tail[:r - (i + 1)]
|
||||
tail += head[: i - r : -1] # head[i + 1:][::-1]
|
||||
tail += head[: i - r: -1] # head[i + 1:][::-1]
|
||||
i += 1
|
||||
head[i:], tail[:] = tail[: r - i], tail[r - i :]
|
||||
head[i:], tail[:] = tail[: r - i], tail[r - i:]
|
||||
|
||||
items = sorted(iterable)
|
||||
|
||||
|
|
@ -811,7 +827,7 @@ def substrings(iterable):
|
|||
# And the rest
|
||||
for n in range(2, item_count + 1):
|
||||
for i in range(item_count - n + 1):
|
||||
yield seq[i : i + n]
|
||||
yield seq[i: i + n]
|
||||
|
||||
|
||||
def substrings_indexes(seq, reverse=False):
|
||||
|
|
@ -844,7 +860,7 @@ def substrings_indexes(seq, reverse=False):
|
|||
if reverse:
|
||||
r = reversed(r)
|
||||
return (
|
||||
(seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)
|
||||
(seq[i: i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1046,9 +1062,9 @@ def collapse(iterable, base_type=None, levels=None):
|
|||
|
||||
def walk(node, level):
|
||||
if (
|
||||
((levels is not None) and (level > levels))
|
||||
or isinstance(node, (str, bytes))
|
||||
or ((base_type is not None) and isinstance(node, base_type))
|
||||
((levels is not None) and (level > levels)) or
|
||||
isinstance(node, (str, bytes)) or
|
||||
((base_type is not None) and isinstance(node, base_type))
|
||||
):
|
||||
yield node
|
||||
return
|
||||
|
|
@ -1146,13 +1162,13 @@ def sliced(seq, n, strict=False):
|
|||
For non-sliceable iterables, see :func:`chunked`.
|
||||
|
||||
"""
|
||||
iterator = takewhile(len, (seq[i : i + n] for i in count(0, n)))
|
||||
iterator = takewhile(len, (seq[i: i + n] for i in count(0, n)))
|
||||
if strict:
|
||||
|
||||
def ret():
|
||||
for _slice in iterator:
|
||||
if len(_slice) != n:
|
||||
raise ValueError("seq is not divisible by n.")
|
||||
raise ValueError('seq is not divisible by n.')
|
||||
yield _slice
|
||||
|
||||
return iter(ret())
|
||||
|
|
@ -1475,7 +1491,7 @@ def stagger(iterable, offsets=(-1, 0, 1), longest=False, fillvalue=None):
|
|||
children = tee(iterable, len(offsets))
|
||||
|
||||
return zip_offset(
|
||||
*children, offsets=offsets, longest=longest, fillvalue=fillvalue
|
||||
*children, offsets=offsets, longest=longest, fillvalue=fillvalue,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1484,7 +1500,7 @@ class UnequalIterablesError(ValueError):
|
|||
msg = 'Iterables have different lengths'
|
||||
if details is not None:
|
||||
msg += (': index 0 has length {}; index {} has length {}').format(
|
||||
*details
|
||||
*details,
|
||||
)
|
||||
|
||||
super().__init__(msg)
|
||||
|
|
@ -1635,17 +1651,18 @@ def sort_together(iterables, key_list=(0,), key=None, reverse=False):
|
|||
# if key_list contains a single item, pass the item at that offset
|
||||
# as the only argument to the key function
|
||||
key_offset = key_list[0]
|
||||
key_argument = lambda zipped_items: key(zipped_items[key_offset])
|
||||
def key_argument(zipped_items): return key(zipped_items[key_offset])
|
||||
else:
|
||||
# if key_list contains multiple items, use itemgetter to return a
|
||||
# tuple of items, which we pass as *args to the key function
|
||||
get_key_items = itemgetter(*key_list)
|
||||
key_argument = lambda zipped_items: key(
|
||||
*get_key_items(zipped_items)
|
||||
|
||||
def key_argument(zipped_items): return key(
|
||||
*get_key_items(zipped_items),
|
||||
)
|
||||
|
||||
return list(
|
||||
zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse))
|
||||
zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse)),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1954,12 +1971,12 @@ class numeric_range(abc.Sequence, abc.Hashable):
|
|||
elif argc == 0:
|
||||
raise TypeError(
|
||||
'numeric_range expected at least '
|
||||
'1 argument, got {}'.format(argc)
|
||||
'1 argument, got {}'.format(argc),
|
||||
)
|
||||
else:
|
||||
raise TypeError(
|
||||
'numeric_range expected at most '
|
||||
'3 arguments, got {}'.format(argc)
|
||||
'3 arguments, got {}'.format(argc),
|
||||
)
|
||||
|
||||
self._zero = type(self._step)(0)
|
||||
|
|
@ -1992,9 +2009,9 @@ class numeric_range(abc.Sequence, abc.Hashable):
|
|||
return empty_self and empty_other # True if both empty
|
||||
else:
|
||||
return (
|
||||
self._start == other._start
|
||||
and self._step == other._step
|
||||
and self._get_by_index(-1) == other._get_by_index(-1)
|
||||
self._start == other._start and
|
||||
self._step == other._step and
|
||||
self._get_by_index(-1) == other._get_by_index(-1)
|
||||
)
|
||||
else:
|
||||
return False
|
||||
|
|
@ -2023,7 +2040,7 @@ class numeric_range(abc.Sequence, abc.Hashable):
|
|||
else:
|
||||
raise TypeError(
|
||||
'numeric range indices must be '
|
||||
'integers or slices, not {}'.format(type(key).__name__)
|
||||
'integers or slices, not {}'.format(type(key).__name__),
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
|
|
@ -2063,19 +2080,19 @@ class numeric_range(abc.Sequence, abc.Hashable):
|
|||
|
||||
def __repr__(self):
|
||||
if self._step == 1:
|
||||
return "numeric_range({}, {})".format(
|
||||
repr(self._start), repr(self._stop)
|
||||
return 'numeric_range({}, {})'.format(
|
||||
repr(self._start), repr(self._stop),
|
||||
)
|
||||
else:
|
||||
return "numeric_range({}, {}, {})".format(
|
||||
repr(self._start), repr(self._stop), repr(self._step)
|
||||
return 'numeric_range({}, {}, {})'.format(
|
||||
repr(self._start), repr(self._stop), repr(self._step),
|
||||
)
|
||||
|
||||
def __reversed__(self):
|
||||
return iter(
|
||||
numeric_range(
|
||||
self._get_by_index(-1), self._start - self._step, -self._step
|
||||
)
|
||||
self._get_by_index(-1), self._start - self._step, -self._step,
|
||||
),
|
||||
)
|
||||
|
||||
def count(self, value):
|
||||
|
|
@ -2093,13 +2110,13 @@ class numeric_range(abc.Sequence, abc.Hashable):
|
|||
if r == self._zero:
|
||||
return int(q)
|
||||
|
||||
raise ValueError("{} is not in numeric range".format(value))
|
||||
raise ValueError(f'{value} is not in numeric range')
|
||||
|
||||
def _get_by_index(self, i):
|
||||
if i < 0:
|
||||
i += self._len
|
||||
if i < 0 or i >= self._len:
|
||||
raise IndexError("numeric range object index out of range")
|
||||
raise IndexError('numeric range object index out of range')
|
||||
return self._start + i * self._step
|
||||
|
||||
|
||||
|
|
@ -2468,7 +2485,7 @@ def consecutive_groups(iterable, ordering=lambda x: x):
|
|||
|
||||
"""
|
||||
for k, g in groupby(
|
||||
enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
|
||||
enumerate(iterable), key=lambda x: x[0] - ordering(x[1]),
|
||||
):
|
||||
yield map(itemgetter(1), g)
|
||||
|
||||
|
|
@ -2557,7 +2574,7 @@ class SequenceView(Sequence):
|
|||
return len(self._target)
|
||||
|
||||
def __repr__(self):
|
||||
return '{}({})'.format(self.__class__.__name__, repr(self._target))
|
||||
return f'{self.__class__.__name__}({repr(self._target)})'
|
||||
|
||||
|
||||
class seekable:
|
||||
|
|
@ -3043,7 +3060,7 @@ def set_partitions(iterable, k=None):
|
|||
if k is not None:
|
||||
if k < 1:
|
||||
raise ValueError(
|
||||
"Can't partition in a negative or zero number of groups"
|
||||
"Can't partition in a negative or zero number of groups",
|
||||
)
|
||||
elif k > n:
|
||||
return
|
||||
|
|
@ -3060,7 +3077,7 @@ def set_partitions(iterable, k=None):
|
|||
yield [[e], *p]
|
||||
for p in set_partitions_helper(M, k):
|
||||
for i in range(len(p)):
|
||||
yield p[:i] + [[e] + p[i]] + p[i + 1 :]
|
||||
yield p[:i] + [[e] + p[i]] + p[i + 1:]
|
||||
|
||||
if k is None:
|
||||
for k in range(1, n + 1):
|
||||
|
|
@ -3225,9 +3242,9 @@ def distinct_combinations(iterable, r):
|
|||
else:
|
||||
generators.append(
|
||||
unique_everseen(
|
||||
enumerate(pool[cur_idx + 1 :], cur_idx + 1),
|
||||
enumerate(pool[cur_idx + 1:], cur_idx + 1),
|
||||
key=itemgetter(1),
|
||||
)
|
||||
),
|
||||
)
|
||||
level += 1
|
||||
|
||||
|
|
@ -3493,7 +3510,7 @@ class callback_iter:
|
|||
q.put((args, kwargs))
|
||||
|
||||
self._future = self._executor.submit(
|
||||
self._func, **{self._callback_kwd: callback}
|
||||
self._func, **{self._callback_kwd: callback},
|
||||
)
|
||||
|
||||
while True:
|
||||
|
|
@ -3556,8 +3573,8 @@ def windowed_complete(iterable, n):
|
|||
|
||||
for i in range(size - n + 1):
|
||||
beginning = seq[:i]
|
||||
middle = seq[i : i + n]
|
||||
end = seq[i + n :]
|
||||
middle = seq[i: i + n]
|
||||
end = seq[i + n:]
|
||||
yield beginning, middle, end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,22 +7,24 @@ Some backward-compatible usability improvements have been made.
|
|||
.. [1] http://docs.python.org/library/itertools.html#recipes
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import operator
|
||||
import warnings
|
||||
from collections import deque
|
||||
from itertools import (
|
||||
chain,
|
||||
combinations,
|
||||
count,
|
||||
cycle,
|
||||
groupby,
|
||||
islice,
|
||||
repeat,
|
||||
starmap,
|
||||
tee,
|
||||
zip_longest,
|
||||
)
|
||||
import operator
|
||||
from random import randrange, sample, choice
|
||||
from itertools import chain
|
||||
from itertools import combinations
|
||||
from itertools import count
|
||||
from itertools import cycle
|
||||
from itertools import groupby
|
||||
from itertools import islice
|
||||
from itertools import repeat
|
||||
from itertools import starmap
|
||||
from itertools import tee
|
||||
from itertools import zip_longest
|
||||
from random import choice
|
||||
from random import randrange
|
||||
from random import sample
|
||||
|
||||
__all__ = [
|
||||
'all_equal',
|
||||
|
|
@ -290,7 +292,7 @@ def grouper(iterable, n, fillvalue=None):
|
|||
"""
|
||||
if isinstance(iterable, int):
|
||||
warnings.warn(
|
||||
"grouper expects iterable as first parameter", DeprecationWarning
|
||||
'grouper expects iterable as first parameter', DeprecationWarning,
|
||||
)
|
||||
n, iterable = iterable, n
|
||||
args = [iter(iterable)] * n
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ entry has an index that can be looked up.
|
|||
Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger,
|
||||
and released under the MIT license.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools as it
|
||||
from collections import deque
|
||||
|
||||
|
|
@ -13,10 +15,10 @@ try:
|
|||
from collections.abc import MutableSet, Sequence
|
||||
except ImportError:
|
||||
# Python 2.7
|
||||
from collections import MutableSet, Sequence
|
||||
from collections.abc import MutableSet, Sequence
|
||||
|
||||
SLICE_ALL = slice(None)
|
||||
__version__ = "3.1"
|
||||
__version__ = '3.1'
|
||||
|
||||
|
||||
def is_iterable(obj):
|
||||
|
|
@ -33,9 +35,9 @@ def is_iterable(obj):
|
|||
have an `__iter__` attribute anyway.
|
||||
"""
|
||||
return (
|
||||
hasattr(obj, "__iter__")
|
||||
and not isinstance(obj, str)
|
||||
and not isinstance(obj, tuple)
|
||||
hasattr(obj, '__iter__') and
|
||||
not isinstance(obj, str) and
|
||||
not isinstance(obj, tuple)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -89,7 +91,7 @@ class OrderedSet(MutableSet, Sequence):
|
|||
return self.copy()
|
||||
elif is_iterable(index):
|
||||
return [self.items[i] for i in index]
|
||||
elif hasattr(index, "__index__") or isinstance(index, slice):
|
||||
elif hasattr(index, '__index__') or isinstance(index, slice):
|
||||
result = self.items[index]
|
||||
if isinstance(result, list):
|
||||
return self.__class__(result)
|
||||
|
|
@ -181,7 +183,7 @@ class OrderedSet(MutableSet, Sequence):
|
|||
item_index = self.add(item)
|
||||
except TypeError:
|
||||
raise ValueError(
|
||||
"Argument needs to be an iterable, got %s" % type(sequence)
|
||||
'Argument needs to be an iterable, got %s' % type(sequence),
|
||||
)
|
||||
return item_index
|
||||
|
||||
|
|
@ -218,7 +220,7 @@ class OrderedSet(MutableSet, Sequence):
|
|||
3
|
||||
"""
|
||||
if not self.items:
|
||||
raise KeyError("Set is empty")
|
||||
raise KeyError('Set is empty')
|
||||
|
||||
elem = self.items[-1]
|
||||
del self.items[-1]
|
||||
|
|
@ -274,8 +276,8 @@ class OrderedSet(MutableSet, Sequence):
|
|||
|
||||
def __repr__(self):
|
||||
if not self:
|
||||
return "%s()" % (self.__class__.__name__,)
|
||||
return "%s(%r)" % (self.__class__.__name__, list(self))
|
||||
return '{}()'.format(self.__class__.__name__)
|
||||
return '{}({!r})'.format(self.__class__.__name__, list(self))
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
|
|
@ -484,5 +486,5 @@ class OrderedSet(MutableSet, Sequence):
|
|||
items_to_add = [item for item in other if item not in self]
|
||||
items_to_remove = set(other)
|
||||
self._update_items(
|
||||
[item for item in self.items if item not in items_to_remove] + items_to_add
|
||||
[item for item in self.items if item not in items_to_remove] + items_to_add,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = [
|
||||
"__title__",
|
||||
"__summary__",
|
||||
"__uri__",
|
||||
"__version__",
|
||||
"__author__",
|
||||
"__email__",
|
||||
"__license__",
|
||||
"__copyright__",
|
||||
'__title__',
|
||||
'__summary__',
|
||||
'__uri__',
|
||||
'__version__',
|
||||
'__author__',
|
||||
'__email__',
|
||||
'__license__',
|
||||
'__copyright__',
|
||||
]
|
||||
|
||||
__title__ = "packaging"
|
||||
__summary__ = "Core utilities for Python packages"
|
||||
__uri__ = "https://github.com/pypa/packaging"
|
||||
__title__ = 'packaging'
|
||||
__summary__ = 'Core utilities for Python packages'
|
||||
__uri__ = 'https://github.com/pypa/packaging'
|
||||
|
||||
__version__ = "20.4"
|
||||
__version__ = '20.4'
|
||||
|
||||
__author__ = "Donald Stufft and individual contributors"
|
||||
__email__ = "donald@stufft.io"
|
||||
__author__ = 'Donald Stufft and individual contributors'
|
||||
__email__ = 'donald@stufft.io'
|
||||
|
||||
__license__ = "BSD-2-Clause or Apache-2.0"
|
||||
__copyright__ = "Copyright 2014-2019 %s" % __author__
|
||||
__license__ = 'BSD-2-Clause or Apache-2.0'
|
||||
__copyright__ = 'Copyright 2014-2019 %s' % __author__
|
||||
|
|
|
|||
|
|
@ -1,26 +1,24 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
from .__about__ import (
|
||||
__author__,
|
||||
__copyright__,
|
||||
__email__,
|
||||
__license__,
|
||||
__summary__,
|
||||
__title__,
|
||||
__uri__,
|
||||
__version__,
|
||||
)
|
||||
from .__about__ import __author__
|
||||
from .__about__ import __copyright__
|
||||
from .__about__ import __email__
|
||||
from .__about__ import __license__
|
||||
from .__about__ import __summary__
|
||||
from .__about__ import __title__
|
||||
from .__about__ import __uri__
|
||||
from .__about__ import __version__
|
||||
|
||||
__all__ = [
|
||||
"__title__",
|
||||
"__summary__",
|
||||
"__uri__",
|
||||
"__version__",
|
||||
"__author__",
|
||||
"__email__",
|
||||
"__license__",
|
||||
"__copyright__",
|
||||
'__title__',
|
||||
'__summary__',
|
||||
'__uri__',
|
||||
'__version__',
|
||||
'__author__',
|
||||
'__email__',
|
||||
'__license__',
|
||||
'__copyright__',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
|
|
@ -35,4 +35,4 @@ def with_metaclass(meta, *bases):
|
|||
# type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
|
||||
return meta(name, bases, d)
|
||||
|
||||
return type.__new__(metaclass, "temporary_class", (), {})
|
||||
return type.__new__(metaclass, 'temporary_class', (), {})
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class InfinityType(object):
|
||||
class InfinityType:
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "Infinity"
|
||||
return 'Infinity'
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
|
|
@ -45,10 +45,10 @@ class InfinityType(object):
|
|||
Infinity = InfinityType()
|
||||
|
||||
|
||||
class NegativeInfinityType(object):
|
||||
class NegativeInfinityType:
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "-Infinity"
|
||||
return '-Infinity'
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ In packaging, all static-typing related imports should be guarded as follows:
|
|||
|
||||
Ref: https://github.com/python/mypy/issues/3216
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ["TYPE_CHECKING", "cast"]
|
||||
__all__ = ['TYPE_CHECKING', 'cast']
|
||||
|
||||
# The TYPE_CHECKING constant defined by the typing module is False at runtime
|
||||
# but True while type checking.
|
||||
|
|
|
|||
|
|
@ -1,20 +1,27 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import operator
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd
|
||||
from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString
|
||||
from setuptools.extern.pyparsing import Forward
|
||||
from setuptools.extern.pyparsing import Group
|
||||
from setuptools.extern.pyparsing import Literal as L # noqa
|
||||
from setuptools.extern.pyparsing import ParseException
|
||||
from setuptools.extern.pyparsing import ParseResults
|
||||
from setuptools.extern.pyparsing import QuotedString
|
||||
from setuptools.extern.pyparsing import stringEnd
|
||||
from setuptools.extern.pyparsing import stringStart
|
||||
from setuptools.extern.pyparsing import ZeroOrMore
|
||||
|
||||
from ._compat import string_types
|
||||
from ._typing import TYPE_CHECKING
|
||||
from .specifiers import Specifier, InvalidSpecifier
|
||||
from .specifiers import InvalidSpecifier
|
||||
from .specifiers import Specifier
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||
|
|
@ -23,11 +30,11 @@ if TYPE_CHECKING: # pragma: no cover
|
|||
|
||||
|
||||
__all__ = [
|
||||
"InvalidMarker",
|
||||
"UndefinedComparison",
|
||||
"UndefinedEnvironmentName",
|
||||
"Marker",
|
||||
"default_environment",
|
||||
'InvalidMarker',
|
||||
'UndefinedComparison',
|
||||
'UndefinedEnvironmentName',
|
||||
'Marker',
|
||||
'default_environment',
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -50,7 +57,7 @@ class UndefinedEnvironmentName(ValueError):
|
|||
"""
|
||||
|
||||
|
||||
class Node(object):
|
||||
class Node:
|
||||
def __init__(self, value):
|
||||
# type: (Any) -> None
|
||||
self.value = value
|
||||
|
|
@ -61,7 +68,7 @@ class Node(object):
|
|||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
|
||||
return f'<{self.__class__.__name__}({str(self)!r})>'
|
||||
|
||||
def serialize(self):
|
||||
# type: () -> str
|
||||
|
|
@ -77,7 +84,7 @@ class Variable(Node):
|
|||
class Value(Node):
|
||||
def serialize(self):
|
||||
# type: () -> str
|
||||
return '"{0}"'.format(self)
|
||||
return f'"{self}"'
|
||||
|
||||
|
||||
class Op(Node):
|
||||
|
|
@ -87,54 +94,54 @@ class Op(Node):
|
|||
|
||||
|
||||
VARIABLE = (
|
||||
L("implementation_version")
|
||||
| L("platform_python_implementation")
|
||||
| L("implementation_name")
|
||||
| L("python_full_version")
|
||||
| L("platform_release")
|
||||
| L("platform_version")
|
||||
| L("platform_machine")
|
||||
| L("platform_system")
|
||||
| L("python_version")
|
||||
| L("sys_platform")
|
||||
| L("os_name")
|
||||
| L("os.name") # PEP-345
|
||||
| L("sys.platform") # PEP-345
|
||||
| L("platform.version") # PEP-345
|
||||
| L("platform.machine") # PEP-345
|
||||
| L("platform.python_implementation") # PEP-345
|
||||
| L("python_implementation") # undocumented setuptools legacy
|
||||
| L("extra") # PEP-508
|
||||
L('implementation_version') |
|
||||
L('platform_python_implementation') |
|
||||
L('implementation_name') |
|
||||
L('python_full_version') |
|
||||
L('platform_release') |
|
||||
L('platform_version') |
|
||||
L('platform_machine') |
|
||||
L('platform_system') |
|
||||
L('python_version') |
|
||||
L('sys_platform') |
|
||||
L('os_name') |
|
||||
L('os.name') | # PEP-345
|
||||
L('sys.platform') | # PEP-345
|
||||
L('platform.version') | # PEP-345
|
||||
L('platform.machine') | # PEP-345
|
||||
L('platform.python_implementation') | # PEP-345
|
||||
L('python_implementation') | # undocumented setuptools legacy
|
||||
L('extra') # PEP-508
|
||||
)
|
||||
ALIASES = {
|
||||
"os.name": "os_name",
|
||||
"sys.platform": "sys_platform",
|
||||
"platform.version": "platform_version",
|
||||
"platform.machine": "platform_machine",
|
||||
"platform.python_implementation": "platform_python_implementation",
|
||||
"python_implementation": "platform_python_implementation",
|
||||
'os.name': 'os_name',
|
||||
'sys.platform': 'sys_platform',
|
||||
'platform.version': 'platform_version',
|
||||
'platform.machine': 'platform_machine',
|
||||
'platform.python_implementation': 'platform_python_implementation',
|
||||
'python_implementation': 'platform_python_implementation',
|
||||
}
|
||||
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
|
||||
|
||||
VERSION_CMP = (
|
||||
L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
|
||||
L('===') | L('==') | L('>=') | L('<=') | L('!=') | L('~=') | L('>') | L('<')
|
||||
)
|
||||
|
||||
MARKER_OP = VERSION_CMP | L("not in") | L("in")
|
||||
MARKER_OP = VERSION_CMP | L('not in') | L('in')
|
||||
MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
|
||||
|
||||
MARKER_VALUE = QuotedString("'") | QuotedString('"')
|
||||
MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
|
||||
|
||||
BOOLOP = L("and") | L("or")
|
||||
BOOLOP = L('and') | L('or')
|
||||
|
||||
MARKER_VAR = VARIABLE | MARKER_VALUE
|
||||
|
||||
MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
|
||||
MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
|
||||
|
||||
LPAREN = L("(").suppress()
|
||||
RPAREN = L(")").suppress()
|
||||
LPAREN = L('(').suppress()
|
||||
RPAREN = L(')').suppress()
|
||||
|
||||
MARKER_EXPR = Forward()
|
||||
MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
|
||||
|
|
@ -161,40 +168,40 @@ def _format_marker(marker, first=True):
|
|||
# the rest of this function so that we don't get extraneous () on the
|
||||
# outside.
|
||||
if (
|
||||
isinstance(marker, list)
|
||||
and len(marker) == 1
|
||||
and isinstance(marker[0], (list, tuple))
|
||||
isinstance(marker, list) and
|
||||
len(marker) == 1 and
|
||||
isinstance(marker[0], (list, tuple))
|
||||
):
|
||||
return _format_marker(marker[0])
|
||||
|
||||
if isinstance(marker, list):
|
||||
inner = (_format_marker(m, first=False) for m in marker)
|
||||
if first:
|
||||
return " ".join(inner)
|
||||
return ' '.join(inner)
|
||||
else:
|
||||
return "(" + " ".join(inner) + ")"
|
||||
return '(' + ' '.join(inner) + ')'
|
||||
elif isinstance(marker, tuple):
|
||||
return " ".join([m.serialize() for m in marker])
|
||||
return ' '.join([m.serialize() for m in marker])
|
||||
else:
|
||||
return marker
|
||||
|
||||
|
||||
_operators = {
|
||||
"in": lambda lhs, rhs: lhs in rhs,
|
||||
"not in": lambda lhs, rhs: lhs not in rhs,
|
||||
"<": operator.lt,
|
||||
"<=": operator.le,
|
||||
"==": operator.eq,
|
||||
"!=": operator.ne,
|
||||
">=": operator.ge,
|
||||
">": operator.gt,
|
||||
'in': lambda lhs, rhs: lhs in rhs,
|
||||
'not in': lambda lhs, rhs: lhs not in rhs,
|
||||
'<': operator.lt,
|
||||
'<=': operator.le,
|
||||
'==': operator.eq,
|
||||
'!=': operator.ne,
|
||||
'>=': operator.ge,
|
||||
'>': operator.gt,
|
||||
} # type: Dict[str, Operator]
|
||||
|
||||
|
||||
def _eval_op(lhs, op, rhs):
|
||||
# type: (str, Op, str) -> bool
|
||||
try:
|
||||
spec = Specifier("".join([op.serialize(), rhs]))
|
||||
spec = Specifier(''.join([op.serialize(), rhs]))
|
||||
except InvalidSpecifier:
|
||||
pass
|
||||
else:
|
||||
|
|
@ -203,13 +210,13 @@ def _eval_op(lhs, op, rhs):
|
|||
oper = _operators.get(op.serialize()) # type: Optional[Operator]
|
||||
if oper is None:
|
||||
raise UndefinedComparison(
|
||||
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
|
||||
f'Undefined {op!r} on {lhs!r} and {rhs!r}.',
|
||||
)
|
||||
|
||||
return oper(lhs, rhs)
|
||||
|
||||
|
||||
class Undefined(object):
|
||||
class Undefined:
|
||||
pass
|
||||
|
||||
|
||||
|
|
@ -222,7 +229,7 @@ def _get_env(environment, name):
|
|||
|
||||
if isinstance(value, Undefined):
|
||||
raise UndefinedEnvironmentName(
|
||||
"{0!r} does not exist in evaluation environment.".format(name)
|
||||
f'{name!r} does not exist in evaluation environment.',
|
||||
)
|
||||
|
||||
return value
|
||||
|
|
@ -249,8 +256,8 @@ def _evaluate_markers(markers, environment):
|
|||
|
||||
groups[-1].append(_eval_op(lhs_value, op, rhs_value))
|
||||
else:
|
||||
assert marker in ["and", "or"]
|
||||
if marker == "or":
|
||||
assert marker in ['and', 'or']
|
||||
if marker == 'or':
|
||||
groups.append([])
|
||||
|
||||
return any(all(item) for item in groups)
|
||||
|
|
@ -258,48 +265,48 @@ def _evaluate_markers(markers, environment):
|
|||
|
||||
def format_full_version(info):
|
||||
# type: (sys._version_info) -> str
|
||||
version = "{0.major}.{0.minor}.{0.micro}".format(info)
|
||||
version = '{0.major}.{0.minor}.{0.micro}'.format(info)
|
||||
kind = info.releaselevel
|
||||
if kind != "final":
|
||||
if kind != 'final':
|
||||
version += kind[0] + str(info.serial)
|
||||
return version
|
||||
|
||||
|
||||
def default_environment():
|
||||
# type: () -> Dict[str, str]
|
||||
if hasattr(sys, "implementation"):
|
||||
if hasattr(sys, 'implementation'):
|
||||
# Ignoring the `sys.implementation` reference for type checking due to
|
||||
# mypy not liking that the attribute doesn't exist in Python 2.7 when
|
||||
# run with the `--py27` flag.
|
||||
iver = format_full_version(sys.implementation.version) # type: ignore
|
||||
implementation_name = sys.implementation.name # type: ignore
|
||||
else:
|
||||
iver = "0"
|
||||
implementation_name = ""
|
||||
iver = '0'
|
||||
implementation_name = ''
|
||||
|
||||
return {
|
||||
"implementation_name": implementation_name,
|
||||
"implementation_version": iver,
|
||||
"os_name": os.name,
|
||||
"platform_machine": platform.machine(),
|
||||
"platform_release": platform.release(),
|
||||
"platform_system": platform.system(),
|
||||
"platform_version": platform.version(),
|
||||
"python_full_version": platform.python_version(),
|
||||
"platform_python_implementation": platform.python_implementation(),
|
||||
"python_version": ".".join(platform.python_version_tuple()[:2]),
|
||||
"sys_platform": sys.platform,
|
||||
'implementation_name': implementation_name,
|
||||
'implementation_version': iver,
|
||||
'os_name': os.name,
|
||||
'platform_machine': platform.machine(),
|
||||
'platform_release': platform.release(),
|
||||
'platform_system': platform.system(),
|
||||
'platform_version': platform.version(),
|
||||
'python_full_version': platform.python_version(),
|
||||
'platform_python_implementation': platform.python_implementation(),
|
||||
'python_version': '.'.join(platform.python_version_tuple()[:2]),
|
||||
'sys_platform': sys.platform,
|
||||
}
|
||||
|
||||
|
||||
class Marker(object):
|
||||
class Marker:
|
||||
def __init__(self, marker):
|
||||
# type: (str) -> None
|
||||
try:
|
||||
self._markers = _coerce_parse_result(MARKER.parseString(marker))
|
||||
except ParseException as e:
|
||||
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
|
||||
marker, marker[e.loc : e.loc + 8]
|
||||
err_str = 'Invalid marker: {!r}, parse error at {!r}'.format(
|
||||
marker, marker[e.loc: e.loc + 8],
|
||||
)
|
||||
raise InvalidMarker(err_str)
|
||||
|
||||
|
|
@ -309,7 +316,7 @@ class Marker(object):
|
|||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "<Marker({0!r})>".format(str(self))
|
||||
return f'<Marker({str(self)!r})>'
|
||||
|
||||
def evaluate(self, environment=None):
|
||||
# type: (Optional[Dict[str, str]]) -> bool
|
||||
|
|
|
|||
|
|
@ -1,19 +1,29 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import string
|
||||
import re
|
||||
|
||||
from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
|
||||
from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
|
||||
from setuptools.extern.pyparsing import Literal as L # noqa
|
||||
import string
|
||||
from urllib import parse as urlparse
|
||||
|
||||
from setuptools.extern.pyparsing import Combine
|
||||
from setuptools.extern.pyparsing import Literal as L # noqa
|
||||
from setuptools.extern.pyparsing import Optional
|
||||
from setuptools.extern.pyparsing import originalTextFor
|
||||
from setuptools.extern.pyparsing import ParseException
|
||||
from setuptools.extern.pyparsing import Regex
|
||||
from setuptools.extern.pyparsing import stringEnd
|
||||
from setuptools.extern.pyparsing import stringStart
|
||||
from setuptools.extern.pyparsing import Word
|
||||
from setuptools.extern.pyparsing import ZeroOrMore
|
||||
|
||||
from ._typing import TYPE_CHECKING
|
||||
from .markers import MARKER_EXPR, Marker
|
||||
from .specifiers import LegacySpecifier, Specifier, SpecifierSet
|
||||
from .markers import Marker
|
||||
from .markers import MARKER_EXPR
|
||||
from .specifiers import LegacySpecifier
|
||||
from .specifiers import Specifier
|
||||
from .specifiers import SpecifierSet
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import List
|
||||
|
|
@ -27,43 +37,43 @@ class InvalidRequirement(ValueError):
|
|||
|
||||
ALPHANUM = Word(string.ascii_letters + string.digits)
|
||||
|
||||
LBRACKET = L("[").suppress()
|
||||
RBRACKET = L("]").suppress()
|
||||
LPAREN = L("(").suppress()
|
||||
RPAREN = L(")").suppress()
|
||||
COMMA = L(",").suppress()
|
||||
SEMICOLON = L(";").suppress()
|
||||
AT = L("@").suppress()
|
||||
LBRACKET = L('[').suppress()
|
||||
RBRACKET = L(']').suppress()
|
||||
LPAREN = L('(').suppress()
|
||||
RPAREN = L(')').suppress()
|
||||
COMMA = L(',').suppress()
|
||||
SEMICOLON = L(';').suppress()
|
||||
AT = L('@').suppress()
|
||||
|
||||
PUNCTUATION = Word("-_.")
|
||||
PUNCTUATION = Word('-_.')
|
||||
IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM)
|
||||
IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
|
||||
|
||||
NAME = IDENTIFIER("name")
|
||||
NAME = IDENTIFIER('name')
|
||||
EXTRA = IDENTIFIER
|
||||
|
||||
URI = Regex(r"[^ ]+")("url")
|
||||
URI = Regex(r'[^ ]+')('url')
|
||||
URL = AT + URI
|
||||
|
||||
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
|
||||
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
|
||||
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)('extras')
|
||||
|
||||
VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
|
||||
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
|
||||
|
||||
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
|
||||
VERSION_MANY = Combine(
|
||||
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
|
||||
)("_raw_spec")
|
||||
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
|
||||
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
|
||||
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=',', adjacent=False,
|
||||
)('_raw_spec')
|
||||
_VERSION_SPEC = Optional((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)
|
||||
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
|
||||
|
||||
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
|
||||
VERSION_SPEC = originalTextFor(_VERSION_SPEC)('specifier')
|
||||
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
|
||||
|
||||
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
|
||||
MARKER_EXPR = originalTextFor(MARKER_EXPR())('marker')
|
||||
MARKER_EXPR.setParseAction(
|
||||
lambda s, l, t: Marker(s[t._original_start : t._original_end])
|
||||
lambda s, l, t: Marker(s[t._original_start: t._original_end]),
|
||||
)
|
||||
MARKER_SEPARATOR = SEMICOLON
|
||||
MARKER = MARKER_SEPARATOR + MARKER_EXPR
|
||||
|
|
@ -76,10 +86,10 @@ NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARK
|
|||
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
|
||||
# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
|
||||
# issue #104
|
||||
REQUIREMENT.parseString("x[]")
|
||||
REQUIREMENT.parseString('x[]')
|
||||
|
||||
|
||||
class Requirement(object):
|
||||
class Requirement:
|
||||
"""Parse a requirement.
|
||||
|
||||
Parse a given requirement string into its parts, such as name, specifier,
|
||||
|
|
@ -98,21 +108,21 @@ class Requirement(object):
|
|||
req = REQUIREMENT.parseString(requirement_string)
|
||||
except ParseException as e:
|
||||
raise InvalidRequirement(
|
||||
'Parse error at "{0!r}": {1}'.format(
|
||||
requirement_string[e.loc : e.loc + 8], e.msg
|
||||
)
|
||||
'Parse error at "{!r}": {}'.format(
|
||||
requirement_string[e.loc: e.loc + 8], e.msg,
|
||||
),
|
||||
)
|
||||
|
||||
self.name = req.name
|
||||
if req.url:
|
||||
parsed_url = urlparse.urlparse(req.url)
|
||||
if parsed_url.scheme == "file":
|
||||
if parsed_url.scheme == 'file':
|
||||
if urlparse.urlunparse(parsed_url) != req.url:
|
||||
raise InvalidRequirement("Invalid URL given")
|
||||
raise InvalidRequirement('Invalid URL given')
|
||||
elif not (parsed_url.scheme and parsed_url.netloc) or (
|
||||
not parsed_url.scheme and not parsed_url.netloc
|
||||
):
|
||||
raise InvalidRequirement("Invalid URL: {0}".format(req.url))
|
||||
raise InvalidRequirement(f'Invalid URL: {req.url}')
|
||||
self.url = req.url
|
||||
else:
|
||||
self.url = None
|
||||
|
|
@ -125,21 +135,21 @@ class Requirement(object):
|
|||
parts = [self.name] # type: List[str]
|
||||
|
||||
if self.extras:
|
||||
parts.append("[{0}]".format(",".join(sorted(self.extras))))
|
||||
parts.append('[{}]'.format(','.join(sorted(self.extras))))
|
||||
|
||||
if self.specifier:
|
||||
parts.append(str(self.specifier))
|
||||
|
||||
if self.url:
|
||||
parts.append("@ {0}".format(self.url))
|
||||
parts.append(f'@ {self.url}')
|
||||
if self.marker:
|
||||
parts.append(" ")
|
||||
parts.append(' ')
|
||||
|
||||
if self.marker:
|
||||
parts.append("; {0}".format(self.marker))
|
||||
parts.append(f'; {self.marker}')
|
||||
|
||||
return "".join(parts)
|
||||
return ''.join(parts)
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "<Requirement({0!r})>".format(str(self))
|
||||
return f'<Requirement({str(self)!r})>'
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import abc
|
||||
import functools
|
||||
import itertools
|
||||
import re
|
||||
|
||||
from ._compat import string_types, with_metaclass
|
||||
from ._compat import string_types
|
||||
from ._compat import with_metaclass
|
||||
from ._typing import TYPE_CHECKING
|
||||
from .utils import canonicalize_version
|
||||
from .version import Version, LegacyVersion, parse
|
||||
from .version import LegacyVersion
|
||||
from .version import parse
|
||||
from .version import Version
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import (
|
||||
|
|
@ -105,15 +108,15 @@ class _IndividualSpecifier(BaseSpecifier):
|
|||
|
||||
_operators = {} # type: Dict[str, str]
|
||||
|
||||
def __init__(self, spec="", prereleases=None):
|
||||
def __init__(self, spec='', prereleases=None):
|
||||
# type: (str, Optional[bool]) -> None
|
||||
match = self._regex.search(spec)
|
||||
if not match:
|
||||
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
|
||||
raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
|
||||
|
||||
self._spec = (
|
||||
match.group("operator").strip(),
|
||||
match.group("version").strip(),
|
||||
match.group('operator').strip(),
|
||||
match.group('version').strip(),
|
||||
) # type: Tuple[str, str]
|
||||
|
||||
# Store whether or not this Specifier should accept prereleases
|
||||
|
|
@ -122,16 +125,16 @@ class _IndividualSpecifier(BaseSpecifier):
|
|||
def __repr__(self):
|
||||
# type: () -> str
|
||||
pre = (
|
||||
", prereleases={0!r}".format(self.prereleases)
|
||||
f', prereleases={self.prereleases!r}'
|
||||
if self._prereleases is not None
|
||||
else ""
|
||||
else ''
|
||||
)
|
||||
|
||||
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
|
||||
return f'<{self.__class__.__name__}({str(self)!r}{pre})>'
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return "{0}{1}".format(*self._spec)
|
||||
return '{}{}'.format(*self._spec)
|
||||
|
||||
@property
|
||||
def _canonical_spec(self):
|
||||
|
|
@ -169,7 +172,7 @@ class _IndividualSpecifier(BaseSpecifier):
|
|||
def _get_operator(self, op):
|
||||
# type: (str) -> CallableOperator
|
||||
operator_callable = getattr(
|
||||
self, "_compare_{0}".format(self._operators[op])
|
||||
self, f'_compare_{self._operators[op]}',
|
||||
) # type: CallableOperator
|
||||
return operator_callable
|
||||
|
||||
|
|
@ -231,7 +234,7 @@ class _IndividualSpecifier(BaseSpecifier):
|
|||
yielded = False
|
||||
found_prereleases = []
|
||||
|
||||
kw = {"prereleases": prereleases if prereleases is not None else True}
|
||||
kw = {'prereleases': prereleases if prereleases is not None else True}
|
||||
|
||||
# Attempt to iterate over all the values in the iterable and if any of
|
||||
# them match, yield them.
|
||||
|
|
@ -274,15 +277,15 @@ class LegacySpecifier(_IndividualSpecifier):
|
|||
)
|
||||
"""
|
||||
|
||||
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
|
||||
_regex = re.compile(r'^\s*' + _regex_str + r'\s*$', re.VERBOSE | re.IGNORECASE)
|
||||
|
||||
_operators = {
|
||||
"==": "equal",
|
||||
"!=": "not_equal",
|
||||
"<=": "less_than_equal",
|
||||
">=": "greater_than_equal",
|
||||
"<": "less_than",
|
||||
">": "greater_than",
|
||||
'==': 'equal',
|
||||
'!=': 'not_equal',
|
||||
'<=': 'less_than_equal',
|
||||
'>=': 'greater_than_equal',
|
||||
'<': 'less_than',
|
||||
'>': 'greater_than',
|
||||
}
|
||||
|
||||
def _coerce_version(self, version):
|
||||
|
|
@ -317,7 +320,7 @@ class LegacySpecifier(_IndividualSpecifier):
|
|||
|
||||
|
||||
def _require_version_compare(
|
||||
fn # type: (Callable[[Specifier, ParsedVersion, str], bool])
|
||||
fn, # type: (Callable[[Specifier, ParsedVersion, str], bool])
|
||||
):
|
||||
# type: (...) -> Callable[[Specifier, ParsedVersion, str], bool]
|
||||
@functools.wraps(fn)
|
||||
|
|
@ -425,17 +428,17 @@ class Specifier(_IndividualSpecifier):
|
|||
)
|
||||
"""
|
||||
|
||||
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
|
||||
_regex = re.compile(r'^\s*' + _regex_str + r'\s*$', re.VERBOSE | re.IGNORECASE)
|
||||
|
||||
_operators = {
|
||||
"~=": "compatible",
|
||||
"==": "equal",
|
||||
"!=": "not_equal",
|
||||
"<=": "less_than_equal",
|
||||
">=": "greater_than_equal",
|
||||
"<": "less_than",
|
||||
">": "greater_than",
|
||||
"===": "arbitrary",
|
||||
'~=': 'compatible',
|
||||
'==': 'equal',
|
||||
'!=': 'not_equal',
|
||||
'<=': 'less_than_equal',
|
||||
'>=': 'greater_than_equal',
|
||||
'<': 'less_than',
|
||||
'>': 'greater_than',
|
||||
'===': 'arbitrary',
|
||||
}
|
||||
|
||||
@_require_version_compare
|
||||
|
|
@ -451,20 +454,20 @@ class Specifier(_IndividualSpecifier):
|
|||
# We want everything but the last item in the version, but we want to
|
||||
# ignore post and dev releases and we want to treat the pre-release as
|
||||
# it's own separate segment.
|
||||
prefix = ".".join(
|
||||
prefix = '.'.join(
|
||||
list(
|
||||
itertools.takewhile(
|
||||
lambda x: (not x.startswith("post") and not x.startswith("dev")),
|
||||
lambda x: (not x.startswith('post') and not x.startswith('dev')),
|
||||
_version_split(spec),
|
||||
)
|
||||
)[:-1]
|
||||
),
|
||||
)[:-1],
|
||||
)
|
||||
|
||||
# Add the prefix notation to the end of our string
|
||||
prefix += ".*"
|
||||
prefix += '.*'
|
||||
|
||||
return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
|
||||
prospective, prefix
|
||||
return self._get_operator('>=')(prospective, spec) and self._get_operator('==')(
|
||||
prospective, prefix,
|
||||
)
|
||||
|
||||
@_require_version_compare
|
||||
|
|
@ -472,7 +475,7 @@ class Specifier(_IndividualSpecifier):
|
|||
# type: (ParsedVersion, str) -> bool
|
||||
|
||||
# We need special logic to handle prefix matching
|
||||
if spec.endswith(".*"):
|
||||
if spec.endswith('.*'):
|
||||
# In the case of prefix matching we want to ignore local segment.
|
||||
prospective = Version(prospective.public)
|
||||
# Split the spec out by dots, and pretend that there is an implicit
|
||||
|
|
@ -492,7 +495,7 @@ class Specifier(_IndividualSpecifier):
|
|||
# Pad out our two sides with zeros so that they both equal the same
|
||||
# length.
|
||||
padded_spec, padded_prospective = _pad_version(
|
||||
split_spec, shortened_prospective
|
||||
split_spec, shortened_prospective,
|
||||
)
|
||||
|
||||
return padded_prospective == padded_spec
|
||||
|
|
@ -608,10 +611,10 @@ class Specifier(_IndividualSpecifier):
|
|||
# operators, and if they are if they are including an explicit
|
||||
# prerelease.
|
||||
operator, version = self._spec
|
||||
if operator in ["==", ">=", "<=", "~=", "==="]:
|
||||
if operator in ['==', '>=', '<=', '~=', '===']:
|
||||
# The == specifier can include a trailing .*, if it does we
|
||||
# want to remove before parsing.
|
||||
if operator == "==" and version.endswith(".*"):
|
||||
if operator == '==' and version.endswith('.*'):
|
||||
version = version[:-2]
|
||||
|
||||
# Parse the version, and if it is a pre-release than this
|
||||
|
|
@ -627,13 +630,13 @@ class Specifier(_IndividualSpecifier):
|
|||
self._prereleases = value
|
||||
|
||||
|
||||
_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
|
||||
_prefix_regex = re.compile(r'^([0-9]+)((?:a|b|c|rc)[0-9]+)$')
|
||||
|
||||
|
||||
def _version_split(version):
|
||||
# type: (str) -> List[str]
|
||||
result = [] # type: List[str]
|
||||
for item in version.split("."):
|
||||
for item in version.split('.'):
|
||||
match = _prefix_regex.search(item)
|
||||
if match:
|
||||
result.extend(match.groups())
|
||||
|
|
@ -651,23 +654,23 @@ def _pad_version(left, right):
|
|||
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
|
||||
|
||||
# Get the rest of our versions
|
||||
left_split.append(left[len(left_split[0]) :])
|
||||
right_split.append(right[len(right_split[0]) :])
|
||||
left_split.append(left[len(left_split[0]):])
|
||||
right_split.append(right[len(right_split[0]):])
|
||||
|
||||
# Insert our padding
|
||||
left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
|
||||
right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
|
||||
left_split.insert(1, ['0'] * max(0, len(right_split[0]) - len(left_split[0])))
|
||||
right_split.insert(1, ['0'] * max(0, len(left_split[0]) - len(right_split[0])))
|
||||
|
||||
return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
|
||||
|
||||
|
||||
class SpecifierSet(BaseSpecifier):
|
||||
def __init__(self, specifiers="", prereleases=None):
|
||||
def __init__(self, specifiers='', prereleases=None):
|
||||
# type: (str, Optional[bool]) -> None
|
||||
|
||||
# Split on , to break each individual specifier into it's own item, and
|
||||
# strip each item to remove leading/trailing whitespace.
|
||||
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
|
||||
split_specifiers = [s.strip() for s in specifiers.split(',') if s.strip()]
|
||||
|
||||
# Parsed each individual specifier, attempting first to make it a
|
||||
# Specifier and falling back to a LegacySpecifier.
|
||||
|
|
@ -688,16 +691,16 @@ class SpecifierSet(BaseSpecifier):
|
|||
def __repr__(self):
|
||||
# type: () -> str
|
||||
pre = (
|
||||
", prereleases={0!r}".format(self.prereleases)
|
||||
f', prereleases={self.prereleases!r}'
|
||||
if self._prereleases is not None
|
||||
else ""
|
||||
else ''
|
||||
)
|
||||
|
||||
return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
|
||||
return f'<SpecifierSet({str(self)!r}{pre})>'
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return ",".join(sorted(str(s) for s in self._specs))
|
||||
return ','.join(sorted(str(s) for s in self._specs))
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
|
|
@ -721,8 +724,8 @@ class SpecifierSet(BaseSpecifier):
|
|||
specifier._prereleases = self._prereleases
|
||||
else:
|
||||
raise ValueError(
|
||||
"Cannot combine SpecifierSets with True and False prerelease "
|
||||
"overrides."
|
||||
'Cannot combine SpecifierSets with True and False prerelease '
|
||||
'overrides.',
|
||||
)
|
||||
|
||||
return specifier
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import annotations
|
||||
|
||||
import distutils.util
|
||||
|
||||
|
|
@ -46,18 +45,18 @@ if TYPE_CHECKING: # pragma: no cover
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
INTERPRETER_SHORT_NAMES = {
|
||||
"python": "py", # Generic.
|
||||
"cpython": "cp",
|
||||
"pypy": "pp",
|
||||
"ironpython": "ip",
|
||||
"jython": "jy",
|
||||
'python': 'py', # Generic.
|
||||
'cpython': 'cp',
|
||||
'pypy': 'pp',
|
||||
'ironpython': 'ip',
|
||||
'jython': 'jy',
|
||||
} # type: Dict[str, str]
|
||||
|
||||
|
||||
_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32
|
||||
|
||||
|
||||
class Tag(object):
|
||||
class Tag:
|
||||
"""
|
||||
A representation of the tag triple for a wheel.
|
||||
|
||||
|
|
@ -65,7 +64,7 @@ class Tag(object):
|
|||
is also supported.
|
||||
"""
|
||||
|
||||
__slots__ = ["_interpreter", "_abi", "_platform"]
|
||||
__slots__ = ['_interpreter', '_abi', '_platform']
|
||||
|
||||
def __init__(self, interpreter, abi, platform):
|
||||
# type: (str, str, str) -> None
|
||||
|
|
@ -94,9 +93,9 @@ class Tag(object):
|
|||
return NotImplemented
|
||||
|
||||
return (
|
||||
(self.platform == other.platform)
|
||||
and (self.abi == other.abi)
|
||||
and (self.interpreter == other.interpreter)
|
||||
(self.platform == other.platform) and
|
||||
(self.abi == other.abi) and
|
||||
(self.interpreter == other.interpreter)
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
|
|
@ -105,11 +104,11 @@ class Tag(object):
|
|||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
return "{}-{}-{}".format(self._interpreter, self._abi, self._platform)
|
||||
return f'{self._interpreter}-{self._abi}-{self._platform}'
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "<{self} @ {self_id}>".format(self=self, self_id=id(self))
|
||||
return f'<{self} @ {id(self)}>'
|
||||
|
||||
|
||||
def parse_tag(tag):
|
||||
|
|
@ -121,10 +120,10 @@ def parse_tag(tag):
|
|||
compressed tag set.
|
||||
"""
|
||||
tags = set()
|
||||
interpreters, abis, platforms = tag.split("-")
|
||||
for interpreter in interpreters.split("."):
|
||||
for abi in abis.split("."):
|
||||
for platform_ in platforms.split("."):
|
||||
interpreters, abis, platforms = tag.split('-')
|
||||
for interpreter in interpreters.split('.'):
|
||||
for abi in abis.split('.'):
|
||||
for platform_ in platforms.split('.'):
|
||||
tags.add(Tag(interpreter, abi, platform_))
|
||||
return frozenset(tags)
|
||||
|
||||
|
|
@ -136,13 +135,13 @@ def _warn_keyword_parameter(func_name, kwargs):
|
|||
"""
|
||||
if not kwargs:
|
||||
return False
|
||||
elif len(kwargs) > 1 or "warn" not in kwargs:
|
||||
kwargs.pop("warn", None)
|
||||
elif len(kwargs) > 1 or 'warn' not in kwargs:
|
||||
kwargs.pop('warn', None)
|
||||
arg = next(iter(kwargs.keys()))
|
||||
raise TypeError(
|
||||
"{}() got an unexpected keyword argument {!r}".format(func_name, arg)
|
||||
f'{func_name}() got an unexpected keyword argument {arg!r}',
|
||||
)
|
||||
return kwargs["warn"]
|
||||
return kwargs['warn']
|
||||
|
||||
|
||||
def _get_config_var(name, warn=False):
|
||||
|
|
@ -150,14 +149,14 @@ def _get_config_var(name, warn=False):
|
|||
value = sysconfig.get_config_var(name)
|
||||
if value is None and warn:
|
||||
logger.debug(
|
||||
"Config variable '%s' is unset, Python ABI tag may be incorrect", name
|
||||
"Config variable '%s' is unset, Python ABI tag may be incorrect", name,
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
def _normalize_string(string):
|
||||
# type: (str) -> str
|
||||
return string.replace(".", "_").replace("-", "_")
|
||||
return string.replace('.', '_').replace('-', '_')
|
||||
|
||||
|
||||
def _abi3_applies(python_version):
|
||||
|
|
@ -175,33 +174,33 @@ def _cpython_abis(py_version, warn=False):
|
|||
py_version = tuple(py_version) # To allow for version comparison.
|
||||
abis = []
|
||||
version = _version_nodot(py_version[:2])
|
||||
debug = pymalloc = ucs4 = ""
|
||||
with_debug = _get_config_var("Py_DEBUG", warn)
|
||||
has_refcount = hasattr(sys, "gettotalrefcount")
|
||||
debug = pymalloc = ucs4 = ''
|
||||
with_debug = _get_config_var('Py_DEBUG', warn)
|
||||
has_refcount = hasattr(sys, 'gettotalrefcount')
|
||||
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
|
||||
# extension modules is the best option.
|
||||
# https://github.com/pypa/pip/issues/3383#issuecomment-173267692
|
||||
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
|
||||
has_ext = '_d.pyd' in EXTENSION_SUFFIXES
|
||||
if with_debug or (with_debug is None and (has_refcount or has_ext)):
|
||||
debug = "d"
|
||||
debug = 'd'
|
||||
if py_version < (3, 8):
|
||||
with_pymalloc = _get_config_var("WITH_PYMALLOC", warn)
|
||||
with_pymalloc = _get_config_var('WITH_PYMALLOC', warn)
|
||||
if with_pymalloc or with_pymalloc is None:
|
||||
pymalloc = "m"
|
||||
pymalloc = 'm'
|
||||
if py_version < (3, 3):
|
||||
unicode_size = _get_config_var("Py_UNICODE_SIZE", warn)
|
||||
unicode_size = _get_config_var('Py_UNICODE_SIZE', warn)
|
||||
if unicode_size == 4 or (
|
||||
unicode_size is None and sys.maxunicode == 0x10FFFF
|
||||
):
|
||||
ucs4 = "u"
|
||||
ucs4 = 'u'
|
||||
elif debug:
|
||||
# Debug builds can also load "normal" extension modules.
|
||||
# We can also assume no UCS-4 or pymalloc requirement.
|
||||
abis.append("cp{version}".format(version=version))
|
||||
abis.append(f'cp{version}')
|
||||
abis.insert(
|
||||
0,
|
||||
"cp{version}{debug}{pymalloc}{ucs4}".format(
|
||||
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4
|
||||
'cp{version}{debug}{pymalloc}{ucs4}'.format(
|
||||
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4,
|
||||
),
|
||||
)
|
||||
return abis
|
||||
|
|
@ -211,7 +210,7 @@ def cpython_tags(
|
|||
python_version=None, # type: Optional[PythonVersion]
|
||||
abis=None, # type: Optional[Iterable[str]]
|
||||
platforms=None, # type: Optional[Iterable[str]]
|
||||
**kwargs # type: bool
|
||||
**kwargs, # type: bool
|
||||
):
|
||||
# type: (...) -> Iterator[Tag]
|
||||
"""
|
||||
|
|
@ -229,11 +228,11 @@ def cpython_tags(
|
|||
If 'abi3' or 'none' are specified in 'abis' then they will be yielded at
|
||||
their normal position and not at the beginning.
|
||||
"""
|
||||
warn = _warn_keyword_parameter("cpython_tags", kwargs)
|
||||
warn = _warn_keyword_parameter('cpython_tags', kwargs)
|
||||
if not python_version:
|
||||
python_version = sys.version_info[:2]
|
||||
|
||||
interpreter = "cp{}".format(_version_nodot(python_version[:2]))
|
||||
interpreter = f'cp{_version_nodot(python_version[:2])}'
|
||||
|
||||
if abis is None:
|
||||
if len(python_version) > 1:
|
||||
|
|
@ -242,7 +241,7 @@ def cpython_tags(
|
|||
abis = []
|
||||
abis = list(abis)
|
||||
# 'abi3' and 'none' are explicitly handled later.
|
||||
for explicit_abi in ("abi3", "none"):
|
||||
for explicit_abi in ('abi3', 'none'):
|
||||
try:
|
||||
abis.remove(explicit_abi)
|
||||
except ValueError:
|
||||
|
|
@ -253,23 +252,21 @@ def cpython_tags(
|
|||
for platform_ in platforms:
|
||||
yield Tag(interpreter, abi, platform_)
|
||||
if _abi3_applies(python_version):
|
||||
for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms):
|
||||
yield tag
|
||||
for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms):
|
||||
yield tag
|
||||
yield from (Tag(interpreter, 'abi3', platform_) for platform_ in platforms)
|
||||
yield from (Tag(interpreter, 'none', platform_) for platform_ in platforms)
|
||||
|
||||
if _abi3_applies(python_version):
|
||||
for minor_version in range(python_version[1] - 1, 1, -1):
|
||||
for platform_ in platforms:
|
||||
interpreter = "cp{version}".format(
|
||||
version=_version_nodot((python_version[0], minor_version))
|
||||
interpreter = 'cp{version}'.format(
|
||||
version=_version_nodot((python_version[0], minor_version)),
|
||||
)
|
||||
yield Tag(interpreter, "abi3", platform_)
|
||||
yield Tag(interpreter, 'abi3', platform_)
|
||||
|
||||
|
||||
def _generic_abi():
|
||||
# type: () -> Iterator[str]
|
||||
abi = sysconfig.get_config_var("SOABI")
|
||||
abi = sysconfig.get_config_var('SOABI')
|
||||
if abi:
|
||||
yield _normalize_string(abi)
|
||||
|
||||
|
|
@ -278,7 +275,7 @@ def generic_tags(
|
|||
interpreter=None, # type: Optional[str]
|
||||
abis=None, # type: Optional[Iterable[str]]
|
||||
platforms=None, # type: Optional[Iterable[str]]
|
||||
**kwargs # type: bool
|
||||
**kwargs, # type: bool
|
||||
):
|
||||
# type: (...) -> Iterator[Tag]
|
||||
"""
|
||||
|
|
@ -289,17 +286,17 @@ def generic_tags(
|
|||
|
||||
The "none" ABI will be added if it was not explicitly provided.
|
||||
"""
|
||||
warn = _warn_keyword_parameter("generic_tags", kwargs)
|
||||
warn = _warn_keyword_parameter('generic_tags', kwargs)
|
||||
if not interpreter:
|
||||
interp_name = interpreter_name()
|
||||
interp_version = interpreter_version(warn=warn)
|
||||
interpreter = "".join([interp_name, interp_version])
|
||||
interpreter = ''.join([interp_name, interp_version])
|
||||
if abis is None:
|
||||
abis = _generic_abi()
|
||||
platforms = list(platforms or _platform_tags())
|
||||
abis = list(abis)
|
||||
if "none" not in abis:
|
||||
abis.append("none")
|
||||
if 'none' not in abis:
|
||||
abis.append('none')
|
||||
for abi in abis:
|
||||
for platform_ in platforms:
|
||||
yield Tag(interpreter, abi, platform_)
|
||||
|
|
@ -314,11 +311,11 @@ def _py_interpreter_range(py_version):
|
|||
all previous versions of that major version.
|
||||
"""
|
||||
if len(py_version) > 1:
|
||||
yield "py{version}".format(version=_version_nodot(py_version[:2]))
|
||||
yield "py{major}".format(major=py_version[0])
|
||||
yield f'py{_version_nodot(py_version[:2])}'
|
||||
yield f'py{py_version[0]}'
|
||||
if len(py_version) > 1:
|
||||
for minor in range(py_version[1] - 1, -1, -1):
|
||||
yield "py{version}".format(version=_version_nodot((py_version[0], minor)))
|
||||
yield f'py{_version_nodot((py_version[0], minor))}'
|
||||
|
||||
|
||||
def compatible_tags(
|
||||
|
|
@ -340,11 +337,11 @@ def compatible_tags(
|
|||
platforms = list(platforms or _platform_tags())
|
||||
for version in _py_interpreter_range(python_version):
|
||||
for platform_ in platforms:
|
||||
yield Tag(version, "none", platform_)
|
||||
yield Tag(version, 'none', platform_)
|
||||
if interpreter:
|
||||
yield Tag(interpreter, "none", "any")
|
||||
yield Tag(interpreter, 'none', 'any')
|
||||
for version in _py_interpreter_range(python_version):
|
||||
yield Tag(version, "none", "any")
|
||||
yield Tag(version, 'none', 'any')
|
||||
|
||||
|
||||
def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
|
||||
|
|
@ -352,37 +349,37 @@ def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
|
|||
if not is_32bit:
|
||||
return arch
|
||||
|
||||
if arch.startswith("ppc"):
|
||||
return "ppc"
|
||||
if arch.startswith('ppc'):
|
||||
return 'ppc'
|
||||
|
||||
return "i386"
|
||||
return 'i386'
|
||||
|
||||
|
||||
def _mac_binary_formats(version, cpu_arch):
|
||||
# type: (MacVersion, str) -> List[str]
|
||||
formats = [cpu_arch]
|
||||
if cpu_arch == "x86_64":
|
||||
if cpu_arch == 'x86_64':
|
||||
if version < (10, 4):
|
||||
return []
|
||||
formats.extend(["intel", "fat64", "fat32"])
|
||||
formats.extend(['intel', 'fat64', 'fat32'])
|
||||
|
||||
elif cpu_arch == "i386":
|
||||
elif cpu_arch == 'i386':
|
||||
if version < (10, 4):
|
||||
return []
|
||||
formats.extend(["intel", "fat32", "fat"])
|
||||
formats.extend(['intel', 'fat32', 'fat'])
|
||||
|
||||
elif cpu_arch == "ppc64":
|
||||
elif cpu_arch == 'ppc64':
|
||||
# TODO: Need to care about 32-bit PPC for ppc64 through 10.2?
|
||||
if version > (10, 5) or version < (10, 4):
|
||||
return []
|
||||
formats.append("fat64")
|
||||
formats.append('fat64')
|
||||
|
||||
elif cpu_arch == "ppc":
|
||||
elif cpu_arch == 'ppc':
|
||||
if version > (10, 6):
|
||||
return []
|
||||
formats.extend(["fat32", "fat"])
|
||||
formats.extend(['fat32', 'fat'])
|
||||
|
||||
formats.append("universal")
|
||||
formats.append('universal')
|
||||
return formats
|
||||
|
||||
|
||||
|
|
@ -398,7 +395,7 @@ def mac_platforms(version=None, arch=None):
|
|||
"""
|
||||
version_str, _, cpu_arch = platform.mac_ver() # type: ignore
|
||||
if version is None:
|
||||
version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
|
||||
version = cast('MacVersion', tuple(map(int, version_str.split('.')[:2])))
|
||||
else:
|
||||
version = version
|
||||
if arch is None:
|
||||
|
|
@ -409,7 +406,7 @@ def mac_platforms(version=None, arch=None):
|
|||
compat_version = version[0], minor_version
|
||||
binary_formats = _mac_binary_formats(compat_version, arch)
|
||||
for binary_format in binary_formats:
|
||||
yield "macosx_{major}_{minor}_{binary_format}".format(
|
||||
yield 'macosx_{major}_{minor}_{binary_format}'.format(
|
||||
major=compat_version[0],
|
||||
minor=compat_version[1],
|
||||
binary_format=binary_format,
|
||||
|
|
@ -423,7 +420,7 @@ def _is_manylinux_compatible(name, glibc_version):
|
|||
try:
|
||||
import _manylinux # noqa
|
||||
|
||||
return bool(getattr(_manylinux, name + "_compatible"))
|
||||
return bool(getattr(_manylinux, name + '_compatible'))
|
||||
except (ImportError, AttributeError):
|
||||
# Fall through to heuristic check below.
|
||||
pass
|
||||
|
|
@ -449,7 +446,7 @@ def _glibc_version_string_confstr():
|
|||
try:
|
||||
# os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17".
|
||||
version_string = os.confstr( # type: ignore[attr-defined] # noqa: F821
|
||||
"CS_GNU_LIBC_VERSION"
|
||||
'CS_GNU_LIBC_VERSION',
|
||||
)
|
||||
assert version_string is not None
|
||||
_, version = version_string.split() # type: Tuple[str, str]
|
||||
|
|
@ -488,7 +485,7 @@ def _glibc_version_string_ctypes():
|
|||
version_str = gnu_get_libc_version() # type: str
|
||||
# py2 / py3 compatibility:
|
||||
if not isinstance(version_str, str):
|
||||
version_str = version_str.decode("ascii")
|
||||
version_str = version_str.decode('ascii')
|
||||
|
||||
return version_str
|
||||
|
||||
|
|
@ -502,17 +499,17 @@ def _check_glibc_version(version_str, required_major, minimum_minor):
|
|||
# random junk that might come after the minor version -- this might happen
|
||||
# in patched/forked versions of glibc (e.g. Linaro's version of glibc
|
||||
# uses version strings like "2.20-2014.11"). See gh-3588.
|
||||
m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
|
||||
m = re.match(r'(?P<major>[0-9]+)\.(?P<minor>[0-9]+)', version_str)
|
||||
if not m:
|
||||
warnings.warn(
|
||||
"Expected glibc version with 2 components major.minor,"
|
||||
" got: %s" % version_str,
|
||||
'Expected glibc version with 2 components major.minor,'
|
||||
' got: %s' % version_str,
|
||||
RuntimeWarning,
|
||||
)
|
||||
return False
|
||||
return (
|
||||
int(m.group("major")) == required_major
|
||||
and int(m.group("minor")) >= minimum_minor
|
||||
int(m.group('major')) == required_major and
|
||||
int(m.group('minor')) >= minimum_minor
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -528,7 +525,7 @@ def _have_compatible_glibc(required_major, minimum_minor):
|
|||
# identify the architecture of the running executable in some cases, so we
|
||||
# determine it dynamically by reading the information from the running
|
||||
# process. This only applies on Linux, which uses the ELF format.
|
||||
class _ELFFileHeader(object):
|
||||
class _ELFFileHeader:
|
||||
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
|
||||
class _InvalidELFFileHeader(ValueError):
|
||||
"""
|
||||
|
|
@ -554,28 +551,28 @@ class _ELFFileHeader(object):
|
|||
# type: (str) -> int
|
||||
try:
|
||||
(result,) = struct.unpack(
|
||||
fmt, file.read(struct.calcsize(fmt))
|
||||
fmt, file.read(struct.calcsize(fmt)),
|
||||
) # type: (int, )
|
||||
except struct.error:
|
||||
raise _ELFFileHeader._InvalidELFFileHeader()
|
||||
return result
|
||||
|
||||
self.e_ident_magic = unpack(">I")
|
||||
self.e_ident_magic = unpack('>I')
|
||||
if self.e_ident_magic != self.ELF_MAGIC_NUMBER:
|
||||
raise _ELFFileHeader._InvalidELFFileHeader()
|
||||
self.e_ident_class = unpack("B")
|
||||
self.e_ident_class = unpack('B')
|
||||
if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}:
|
||||
raise _ELFFileHeader._InvalidELFFileHeader()
|
||||
self.e_ident_data = unpack("B")
|
||||
self.e_ident_data = unpack('B')
|
||||
if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}:
|
||||
raise _ELFFileHeader._InvalidELFFileHeader()
|
||||
self.e_ident_version = unpack("B")
|
||||
self.e_ident_osabi = unpack("B")
|
||||
self.e_ident_abiversion = unpack("B")
|
||||
self.e_ident_version = unpack('B')
|
||||
self.e_ident_osabi = unpack('B')
|
||||
self.e_ident_abiversion = unpack('B')
|
||||
self.e_ident_pad = file.read(7)
|
||||
format_h = "<H" if self.e_ident_data == self.ELFDATA2LSB else ">H"
|
||||
format_i = "<I" if self.e_ident_data == self.ELFDATA2LSB else ">I"
|
||||
format_q = "<Q" if self.e_ident_data == self.ELFDATA2LSB else ">Q"
|
||||
format_h = '<H' if self.e_ident_data == self.ELFDATA2LSB else '>H'
|
||||
format_i = '<I' if self.e_ident_data == self.ELFDATA2LSB else '>I'
|
||||
format_q = '<Q' if self.e_ident_data == self.ELFDATA2LSB else '>Q'
|
||||
format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q
|
||||
self.e_type = unpack(format_h)
|
||||
self.e_machine = unpack(format_h)
|
||||
|
|
@ -595,9 +592,9 @@ class _ELFFileHeader(object):
|
|||
def _get_elf_header():
|
||||
# type: () -> Optional[_ELFFileHeader]
|
||||
try:
|
||||
with open(sys.executable, "rb") as f:
|
||||
with open(sys.executable, 'rb') as f:
|
||||
elf_header = _ELFFileHeader(f)
|
||||
except (IOError, OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
|
||||
except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
|
||||
return None
|
||||
return elf_header
|
||||
|
||||
|
|
@ -635,9 +632,9 @@ def _is_linux_i686():
|
|||
|
||||
def _have_compatible_manylinux_abi(arch):
|
||||
# type: (str) -> bool
|
||||
if arch == "armv7l":
|
||||
if arch == 'armv7l':
|
||||
return _is_linux_armhf()
|
||||
if arch == "i686":
|
||||
if arch == 'i686':
|
||||
return _is_linux_i686()
|
||||
return True
|
||||
|
||||
|
|
@ -646,32 +643,32 @@ def _linux_platforms(is_32bit=_32_BIT_INTERPRETER):
|
|||
# type: (bool) -> Iterator[str]
|
||||
linux = _normalize_string(distutils.util.get_platform())
|
||||
if is_32bit:
|
||||
if linux == "linux_x86_64":
|
||||
linux = "linux_i686"
|
||||
elif linux == "linux_aarch64":
|
||||
linux = "linux_armv7l"
|
||||
if linux == 'linux_x86_64':
|
||||
linux = 'linux_i686'
|
||||
elif linux == 'linux_aarch64':
|
||||
linux = 'linux_armv7l'
|
||||
manylinux_support = []
|
||||
_, arch = linux.split("_", 1)
|
||||
_, arch = linux.split('_', 1)
|
||||
if _have_compatible_manylinux_abi(arch):
|
||||
if arch in {"x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"}:
|
||||
if arch in {'x86_64', 'i686', 'aarch64', 'armv7l', 'ppc64', 'ppc64le', 's390x'}:
|
||||
manylinux_support.append(
|
||||
("manylinux2014", (2, 17))
|
||||
('manylinux2014', (2, 17)),
|
||||
) # CentOS 7 w/ glibc 2.17 (PEP 599)
|
||||
if arch in {"x86_64", "i686"}:
|
||||
if arch in {'x86_64', 'i686'}:
|
||||
manylinux_support.append(
|
||||
("manylinux2010", (2, 12))
|
||||
('manylinux2010', (2, 12)),
|
||||
) # CentOS 6 w/ glibc 2.12 (PEP 571)
|
||||
manylinux_support.append(
|
||||
("manylinux1", (2, 5))
|
||||
('manylinux1', (2, 5)),
|
||||
) # CentOS 5 w/ glibc 2.5 (PEP 513)
|
||||
manylinux_support_iter = iter(manylinux_support)
|
||||
for name, glibc_version in manylinux_support_iter:
|
||||
if _is_manylinux_compatible(name, glibc_version):
|
||||
yield linux.replace("linux", name)
|
||||
yield linux.replace('linux', name)
|
||||
break
|
||||
# Support for a later manylinux implies support for an earlier version.
|
||||
for name, _ in manylinux_support_iter:
|
||||
yield linux.replace("linux", name)
|
||||
yield linux.replace('linux', name)
|
||||
yield linux
|
||||
|
||||
|
||||
|
|
@ -685,9 +682,9 @@ def _platform_tags():
|
|||
"""
|
||||
Provides the platform tags for this installation.
|
||||
"""
|
||||
if platform.system() == "Darwin":
|
||||
if platform.system() == 'Darwin':
|
||||
return mac_platforms()
|
||||
elif platform.system() == "Linux":
|
||||
elif platform.system() == 'Linux':
|
||||
return _linux_platforms()
|
||||
else:
|
||||
return _generic_platforms()
|
||||
|
|
@ -711,8 +708,8 @@ def interpreter_version(**kwargs):
|
|||
"""
|
||||
Returns the version of the running interpreter.
|
||||
"""
|
||||
warn = _warn_keyword_parameter("interpreter_version", kwargs)
|
||||
version = _get_config_var("py_version_nodot", warn=warn)
|
||||
warn = _warn_keyword_parameter('interpreter_version', kwargs)
|
||||
version = _get_config_var('py_version_nodot', warn=warn)
|
||||
if version:
|
||||
version = str(version)
|
||||
else:
|
||||
|
|
@ -723,9 +720,9 @@ def interpreter_version(**kwargs):
|
|||
def _version_nodot(version):
|
||||
# type: (PythonVersion) -> str
|
||||
if any(v >= 10 for v in version):
|
||||
sep = "_"
|
||||
sep = '_'
|
||||
else:
|
||||
sep = ""
|
||||
sep = ''
|
||||
return sep.join(map(str, version))
|
||||
|
||||
|
||||
|
|
@ -737,15 +734,12 @@ def sys_tags(**kwargs):
|
|||
The order of the sequence corresponds to priority order for the
|
||||
interpreter, from most to least important.
|
||||
"""
|
||||
warn = _warn_keyword_parameter("sys_tags", kwargs)
|
||||
warn = _warn_keyword_parameter('sys_tags', kwargs)
|
||||
|
||||
interp_name = interpreter_name()
|
||||
if interp_name == "cp":
|
||||
for tag in cpython_tags(warn=warn):
|
||||
yield tag
|
||||
if interp_name == 'cp':
|
||||
yield from cpython_tags(warn=warn)
|
||||
else:
|
||||
for tag in generic_tags():
|
||||
yield tag
|
||||
yield from generic_tags()
|
||||
|
||||
for tag in compatible_tags():
|
||||
yield tag
|
||||
yield from compatible_tags()
|
||||
|
|
|
|||
|
|
@ -1,26 +1,28 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from ._typing import TYPE_CHECKING, cast
|
||||
from .version import InvalidVersion, Version
|
||||
from ._typing import cast
|
||||
from ._typing import TYPE_CHECKING
|
||||
from .version import InvalidVersion
|
||||
from .version import Version
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import NewType, Union
|
||||
|
||||
NormalizedName = NewType("NormalizedName", str)
|
||||
NormalizedName = NewType('NormalizedName', str)
|
||||
|
||||
_canonicalize_regex = re.compile(r"[-_.]+")
|
||||
_canonicalize_regex = re.compile(r'[-_.]+')
|
||||
|
||||
|
||||
def canonicalize_name(name):
|
||||
# type: (str) -> NormalizedName
|
||||
# This is taken from PEP 503.
|
||||
value = _canonicalize_regex.sub("-", name).lower()
|
||||
return cast("NormalizedName", value)
|
||||
value = _canonicalize_regex.sub('-', name).lower()
|
||||
return cast('NormalizedName', value)
|
||||
|
||||
|
||||
def canonicalize_version(_version):
|
||||
|
|
@ -40,26 +42,26 @@ def canonicalize_version(_version):
|
|||
|
||||
# Epoch
|
||||
if version.epoch != 0:
|
||||
parts.append("{0}!".format(version.epoch))
|
||||
parts.append(f'{version.epoch}!')
|
||||
|
||||
# Release segment
|
||||
# NB: This strips trailing '.0's to normalize
|
||||
parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
|
||||
parts.append(re.sub(r'(\.0)+$', '', '.'.join(str(x) for x in version.release)))
|
||||
|
||||
# Pre-release
|
||||
if version.pre is not None:
|
||||
parts.append("".join(str(x) for x in version.pre))
|
||||
parts.append(''.join(str(x) for x in version.pre))
|
||||
|
||||
# Post-release
|
||||
if version.post is not None:
|
||||
parts.append(".post{0}".format(version.post))
|
||||
parts.append(f'.post{version.post}')
|
||||
|
||||
# Development release
|
||||
if version.dev is not None:
|
||||
parts.append(".dev{0}".format(version.dev))
|
||||
parts.append(f'.dev{version.dev}')
|
||||
|
||||
# Local version segment
|
||||
if version.local is not None:
|
||||
parts.append("+{0}".format(version.local))
|
||||
parts.append(f'+{version.local}')
|
||||
|
||||
return "".join(parts)
|
||||
return ''.join(parts)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
# This file is dual licensed under the terms of the Apache License, Version
|
||||
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
||||
# for complete details.
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from __future__ import annotations
|
||||
|
||||
import collections
|
||||
import itertools
|
||||
import re
|
||||
|
||||
from ._structures import Infinity, NegativeInfinity
|
||||
from ._structures import Infinity
|
||||
from ._structures import NegativeInfinity
|
||||
from ._typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
|
|
@ -30,18 +31,18 @@ if TYPE_CHECKING: # pragma: no cover
|
|||
],
|
||||
]
|
||||
CmpKey = Tuple[
|
||||
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType
|
||||
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType,
|
||||
]
|
||||
LegacyCmpKey = Tuple[int, Tuple[str, ...]]
|
||||
VersionComparisonMethod = Callable[
|
||||
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool
|
||||
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool,
|
||||
]
|
||||
|
||||
__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
|
||||
__all__ = ['parse', 'Version', 'LegacyVersion', 'InvalidVersion', 'VERSION_PATTERN']
|
||||
|
||||
|
||||
_Version = collections.namedtuple(
|
||||
"_Version", ["epoch", "release", "dev", "pre", "post", "local"]
|
||||
'_Version', ['epoch', 'release', 'dev', 'pre', 'post', 'local'],
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ class InvalidVersion(ValueError):
|
|||
"""
|
||||
|
||||
|
||||
class _BaseVersion(object):
|
||||
class _BaseVersion:
|
||||
_key = None # type: Union[CmpKey, LegacyCmpKey]
|
||||
|
||||
def __hash__(self):
|
||||
|
|
@ -115,7 +116,7 @@ class LegacyVersion(_BaseVersion):
|
|||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "<LegacyVersion({0})>".format(repr(str(self)))
|
||||
return f'<LegacyVersion({repr(str(self))})>'
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
|
|
@ -173,14 +174,14 @@ class LegacyVersion(_BaseVersion):
|
|||
return False
|
||||
|
||||
|
||||
_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
|
||||
_legacy_version_component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
|
||||
|
||||
_legacy_version_replacement_map = {
|
||||
"pre": "c",
|
||||
"preview": "c",
|
||||
"-": "final-",
|
||||
"rc": "c",
|
||||
"dev": "@",
|
||||
'pre': 'c',
|
||||
'preview': 'c',
|
||||
'-': 'final-',
|
||||
'rc': 'c',
|
||||
'dev': '@',
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -189,17 +190,17 @@ def _parse_version_parts(s):
|
|||
for part in _legacy_version_component_re.split(s):
|
||||
part = _legacy_version_replacement_map.get(part, part)
|
||||
|
||||
if not part or part == ".":
|
||||
if not part or part == '.':
|
||||
continue
|
||||
|
||||
if part[:1] in "0123456789":
|
||||
if part[:1] in '0123456789':
|
||||
# pad for numeric comparison
|
||||
yield part.zfill(8)
|
||||
else:
|
||||
yield "*" + part
|
||||
yield '*' + part
|
||||
|
||||
# ensure that alpha/beta/candidate are before final
|
||||
yield "*final"
|
||||
yield '*final'
|
||||
|
||||
|
||||
def _legacy_cmpkey(version):
|
||||
|
|
@ -215,14 +216,14 @@ def _legacy_cmpkey(version):
|
|||
# it's adoption of the packaging library.
|
||||
parts = [] # type: List[str]
|
||||
for part in _parse_version_parts(version.lower()):
|
||||
if part.startswith("*"):
|
||||
if part.startswith('*'):
|
||||
# remove "-" before a prerelease tag
|
||||
if part < "*final":
|
||||
while parts and parts[-1] == "*final-":
|
||||
if part < '*final':
|
||||
while parts and parts[-1] == '*final-':
|
||||
parts.pop()
|
||||
|
||||
# remove trailing zeros from each series of numeric parts
|
||||
while parts and parts[-1] == "00000000":
|
||||
while parts and parts[-1] == '00000000':
|
||||
parts.pop()
|
||||
|
||||
parts.append(part)
|
||||
|
|
@ -266,7 +267,7 @@ VERSION_PATTERN = r"""
|
|||
|
||||
class Version(_BaseVersion):
|
||||
|
||||
_regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
|
||||
_regex = re.compile(r'^\s*' + VERSION_PATTERN + r'\s*$', re.VERBOSE | re.IGNORECASE)
|
||||
|
||||
def __init__(self, version):
|
||||
# type: (str) -> None
|
||||
|
|
@ -274,18 +275,18 @@ class Version(_BaseVersion):
|
|||
# Validate the version and parse it into pieces
|
||||
match = self._regex.search(version)
|
||||
if not match:
|
||||
raise InvalidVersion("Invalid version: '{0}'".format(version))
|
||||
raise InvalidVersion(f"Invalid version: '{version}'")
|
||||
|
||||
# Store the parsed out pieces of the version
|
||||
self._version = _Version(
|
||||
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
|
||||
release=tuple(int(i) for i in match.group("release").split(".")),
|
||||
pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
|
||||
epoch=int(match.group('epoch')) if match.group('epoch') else 0,
|
||||
release=tuple(int(i) for i in match.group('release').split('.')),
|
||||
pre=_parse_letter_version(match.group('pre_l'), match.group('pre_n')),
|
||||
post=_parse_letter_version(
|
||||
match.group("post_l"), match.group("post_n1") or match.group("post_n2")
|
||||
match.group('post_l'), match.group('post_n1') or match.group('post_n2'),
|
||||
),
|
||||
dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
|
||||
local=_parse_local_version(match.group("local")),
|
||||
dev=_parse_letter_version(match.group('dev_l'), match.group('dev_n')),
|
||||
local=_parse_local_version(match.group('local')),
|
||||
)
|
||||
|
||||
# Generate a key which will be used for sorting
|
||||
|
|
@ -300,7 +301,7 @@ class Version(_BaseVersion):
|
|||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return "<Version({0})>".format(repr(str(self)))
|
||||
return f'<Version({repr(str(self))})>'
|
||||
|
||||
def __str__(self):
|
||||
# type: () -> str
|
||||
|
|
@ -308,28 +309,28 @@ class Version(_BaseVersion):
|
|||
|
||||
# Epoch
|
||||
if self.epoch != 0:
|
||||
parts.append("{0}!".format(self.epoch))
|
||||
parts.append(f'{self.epoch}!')
|
||||
|
||||
# Release segment
|
||||
parts.append(".".join(str(x) for x in self.release))
|
||||
parts.append('.'.join(str(x) for x in self.release))
|
||||
|
||||
# Pre-release
|
||||
if self.pre is not None:
|
||||
parts.append("".join(str(x) for x in self.pre))
|
||||
parts.append(''.join(str(x) for x in self.pre))
|
||||
|
||||
# Post-release
|
||||
if self.post is not None:
|
||||
parts.append(".post{0}".format(self.post))
|
||||
parts.append(f'.post{self.post}')
|
||||
|
||||
# Development release
|
||||
if self.dev is not None:
|
||||
parts.append(".dev{0}".format(self.dev))
|
||||
parts.append(f'.dev{self.dev}')
|
||||
|
||||
# Local version segment
|
||||
if self.local is not None:
|
||||
parts.append("+{0}".format(self.local))
|
||||
parts.append(f'+{self.local}')
|
||||
|
||||
return "".join(parts)
|
||||
return ''.join(parts)
|
||||
|
||||
@property
|
||||
def epoch(self):
|
||||
|
|
@ -363,14 +364,14 @@ class Version(_BaseVersion):
|
|||
def local(self):
|
||||
# type: () -> Optional[str]
|
||||
if self._version.local:
|
||||
return ".".join(str(x) for x in self._version.local)
|
||||
return '.'.join(str(x) for x in self._version.local)
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def public(self):
|
||||
# type: () -> str
|
||||
return str(self).split("+", 1)[0]
|
||||
return str(self).split('+', 1)[0]
|
||||
|
||||
@property
|
||||
def base_version(self):
|
||||
|
|
@ -379,12 +380,12 @@ class Version(_BaseVersion):
|
|||
|
||||
# Epoch
|
||||
if self.epoch != 0:
|
||||
parts.append("{0}!".format(self.epoch))
|
||||
parts.append(f'{self.epoch}!')
|
||||
|
||||
# Release segment
|
||||
parts.append(".".join(str(x) for x in self.release))
|
||||
parts.append('.'.join(str(x) for x in self.release))
|
||||
|
||||
return "".join(parts)
|
||||
return ''.join(parts)
|
||||
|
||||
@property
|
||||
def is_prerelease(self):
|
||||
|
|
@ -435,27 +436,27 @@ def _parse_letter_version(
|
|||
# We consider some words to be alternate spellings of other words and
|
||||
# in those cases we want to normalize the spellings to our preferred
|
||||
# spelling.
|
||||
if letter == "alpha":
|
||||
letter = "a"
|
||||
elif letter == "beta":
|
||||
letter = "b"
|
||||
elif letter in ["c", "pre", "preview"]:
|
||||
letter = "rc"
|
||||
elif letter in ["rev", "r"]:
|
||||
letter = "post"
|
||||
if letter == 'alpha':
|
||||
letter = 'a'
|
||||
elif letter == 'beta':
|
||||
letter = 'b'
|
||||
elif letter in ['c', 'pre', 'preview']:
|
||||
letter = 'rc'
|
||||
elif letter in ['rev', 'r']:
|
||||
letter = 'post'
|
||||
|
||||
return letter, int(number)
|
||||
if not letter and number:
|
||||
# We assume if we are given a number, but we are not given a letter
|
||||
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
||||
letter = "post"
|
||||
letter = 'post'
|
||||
|
||||
return letter, int(number)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
_local_version_separators = re.compile(r"[\._-]")
|
||||
_local_version_separators = re.compile(r'[\._-]')
|
||||
|
||||
|
||||
def _parse_local_version(local):
|
||||
|
|
@ -487,7 +488,7 @@ def _cmpkey(
|
|||
# re-reverse it back into the correct order and make it a tuple and use
|
||||
# that for our sorting key.
|
||||
_release = tuple(
|
||||
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
|
||||
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))),
|
||||
)
|
||||
|
||||
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
|
||||
|
|
@ -529,7 +530,7 @@ def _cmpkey(
|
|||
# - Shorter versions sort before longer versions when the prefixes
|
||||
# match exactly
|
||||
_local = tuple(
|
||||
(i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
|
||||
(i, '') if isinstance(i, int) else (NegativeInfinity, i) for i in local
|
||||
)
|
||||
|
||||
return epoch, _release, _pre, _post, _dev, _local
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +1,19 @@
|
|||
"""Utilities for extracting common archive formats"""
|
||||
from __future__ import annotations
|
||||
|
||||
import zipfile
|
||||
import tarfile
|
||||
import os
|
||||
import shutil
|
||||
import posixpath
|
||||
import contextlib
|
||||
from distutils.errors import DistutilsError
|
||||
import os
|
||||
import posixpath
|
||||
import shutil
|
||||
import tarfile
|
||||
import zipfile
|
||||
|
||||
from distutils.errors import DistutilsError
|
||||
from pkg_resources import ensure_directory
|
||||
|
||||
__all__ = [
|
||||
"unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
|
||||
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
|
||||
'unpack_archive', 'unpack_zipfile', 'unpack_tarfile', 'default_filter',
|
||||
'UnrecognizedFormat', 'extraction_drivers', 'unpack_directory',
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -27,7 +28,8 @@ def default_filter(src, dst):
|
|||
|
||||
def unpack_archive(
|
||||
filename, extract_dir, progress_filter=default_filter,
|
||||
drivers=None):
|
||||
drivers=None,
|
||||
):
|
||||
"""Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
|
||||
|
||||
`progress_filter` is a function taking two arguments: a source path
|
||||
|
|
@ -57,7 +59,7 @@ def unpack_archive(
|
|||
return
|
||||
else:
|
||||
raise UnrecognizedFormat(
|
||||
"Not a recognized archive type: %s" % filename
|
||||
'Not a recognized archive type: %s' % filename,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -67,7 +69,7 @@ def unpack_directory(filename, extract_dir, progress_filter=default_filter):
|
|||
Raises ``UnrecognizedFormat`` if `filename` is not a directory
|
||||
"""
|
||||
if not os.path.isdir(filename):
|
||||
raise UnrecognizedFormat("%s is not a directory" % filename)
|
||||
raise UnrecognizedFormat('%s is not a directory' % filename)
|
||||
|
||||
paths = {
|
||||
filename: ('', extract_dir),
|
||||
|
|
@ -97,7 +99,7 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
|||
"""
|
||||
|
||||
if not zipfile.is_zipfile(filename):
|
||||
raise UnrecognizedFormat("%s is not a zip file" % (filename,))
|
||||
raise UnrecognizedFormat('{} is not a zip file'.format(filename))
|
||||
|
||||
with zipfile.ZipFile(filename) as z:
|
||||
for info in z.infolist():
|
||||
|
|
@ -128,7 +130,8 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
|||
def _resolve_tar_file_or_dir(tar_obj, tar_member_obj):
|
||||
"""Resolve any links and extract link targets as normal files."""
|
||||
while tar_member_obj is not None and (
|
||||
tar_member_obj.islnk() or tar_member_obj.issym()):
|
||||
tar_member_obj.islnk() or tar_member_obj.issym()
|
||||
):
|
||||
linkpath = tar_member_obj.linkname
|
||||
if tar_member_obj.issym():
|
||||
base = posixpath.dirname(tar_member_obj.name)
|
||||
|
|
@ -186,7 +189,7 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
|||
tarobj = tarfile.open(filename)
|
||||
except tarfile.TarError as e:
|
||||
raise UnrecognizedFormat(
|
||||
"%s is not a compressed or uncompressed tar file" % (filename,)
|
||||
'{} is not a compressed or uncompressed tar file'.format(filename),
|
||||
) from e
|
||||
|
||||
for member, final_dst in _iter_open_tar(
|
||||
|
|
|
|||
|
|
@ -25,27 +25,29 @@ bug reports or API stability):
|
|||
|
||||
Again, this is not a formal definition! Just a "taste" of the module.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import tokenize
|
||||
import shutil
|
||||
import contextlib
|
||||
import sys
|
||||
import tempfile
|
||||
import tokenize
|
||||
|
||||
import setuptools
|
||||
import distutils
|
||||
|
||||
import setuptools
|
||||
from pkg_resources import parse_requirements
|
||||
|
||||
__all__ = ['get_requires_for_build_sdist',
|
||||
'get_requires_for_build_wheel',
|
||||
'prepare_metadata_for_build_wheel',
|
||||
'build_wheel',
|
||||
'build_sdist',
|
||||
'__legacy__',
|
||||
'SetupRequirementsError']
|
||||
__all__ = [
|
||||
'get_requires_for_build_sdist',
|
||||
'get_requires_for_build_wheel',
|
||||
'prepare_metadata_for_build_wheel',
|
||||
'build_wheel',
|
||||
'build_sdist',
|
||||
'__legacy__',
|
||||
'SetupRequirementsError',
|
||||
]
|
||||
|
||||
|
||||
class SetupRequirementsError(BaseException):
|
||||
|
|
@ -92,8 +94,10 @@ def no_install_setup_requires():
|
|||
|
||||
|
||||
def _get_immediate_subdirectories(a_dir):
|
||||
return [name for name in os.listdir(a_dir)
|
||||
if os.path.isdir(os.path.join(a_dir, name))]
|
||||
return [
|
||||
name for name in os.listdir(a_dir)
|
||||
if os.path.isdir(os.path.join(a_dir, name))
|
||||
]
|
||||
|
||||
|
||||
def _file_with_extension(directory, extension):
|
||||
|
|
@ -106,19 +110,20 @@ def _file_with_extension(directory, extension):
|
|||
except ValueError:
|
||||
raise ValueError(
|
||||
'No distribution was found. Ensure that `setup.py` '
|
||||
'is not empty and that it calls `setup()`.')
|
||||
'is not empty and that it calls `setup()`.',
|
||||
)
|
||||
return file
|
||||
|
||||
|
||||
def _open_setup_script(setup_script):
|
||||
if not os.path.exists(setup_script):
|
||||
# Supply a default setup.py
|
||||
return io.StringIO(u"from setuptools import setup; setup()")
|
||||
return io.StringIO('from setuptools import setup; setup()')
|
||||
|
||||
return getattr(tokenize, 'open', open)(setup_script)
|
||||
|
||||
|
||||
class _BuildMetaBackend(object):
|
||||
class _BuildMetaBackend:
|
||||
|
||||
def _fix_config(self, config_settings):
|
||||
config_settings = config_settings or {}
|
||||
|
|
@ -129,7 +134,7 @@ class _BuildMetaBackend(object):
|
|||
config_settings = self._fix_config(config_settings)
|
||||
|
||||
sys.argv = sys.argv[:1] + ['egg_info'] + \
|
||||
config_settings["--global-option"]
|
||||
config_settings['--global-option']
|
||||
try:
|
||||
with Distribution.patch():
|
||||
self.run_setup()
|
||||
|
|
@ -152,23 +157,29 @@ class _BuildMetaBackend(object):
|
|||
def get_requires_for_build_wheel(self, config_settings=None):
|
||||
config_settings = self._fix_config(config_settings)
|
||||
return self._get_build_requires(
|
||||
config_settings, requirements=['wheel'])
|
||||
config_settings, requirements=['wheel'],
|
||||
)
|
||||
|
||||
def get_requires_for_build_sdist(self, config_settings=None):
|
||||
config_settings = self._fix_config(config_settings)
|
||||
return self._get_build_requires(config_settings, requirements=[])
|
||||
|
||||
def prepare_metadata_for_build_wheel(self, metadata_directory,
|
||||
config_settings=None):
|
||||
def prepare_metadata_for_build_wheel(
|
||||
self, metadata_directory,
|
||||
config_settings=None,
|
||||
):
|
||||
sys.argv = sys.argv[:1] + [
|
||||
'dist_info', '--egg-base', metadata_directory]
|
||||
'dist_info', '--egg-base', metadata_directory,
|
||||
]
|
||||
with no_install_setup_requires():
|
||||
self.run_setup()
|
||||
|
||||
dist_info_directory = metadata_directory
|
||||
while True:
|
||||
dist_infos = [f for f in os.listdir(dist_info_directory)
|
||||
if f.endswith('.dist-info')]
|
||||
dist_infos = [
|
||||
f for f in os.listdir(dist_info_directory)
|
||||
if f.endswith('.dist-info')
|
||||
]
|
||||
|
||||
if (
|
||||
len(dist_infos) == 0 and
|
||||
|
|
@ -176,7 +187,8 @@ class _BuildMetaBackend(object):
|
|||
):
|
||||
|
||||
dist_info_directory = os.path.join(
|
||||
dist_info_directory, os.listdir(dist_info_directory)[0])
|
||||
dist_info_directory, os.listdir(dist_info_directory)[0],
|
||||
)
|
||||
continue
|
||||
|
||||
assert len(dist_infos) == 1
|
||||
|
|
@ -187,27 +199,33 @@ class _BuildMetaBackend(object):
|
|||
if dist_info_directory != metadata_directory:
|
||||
shutil.move(
|
||||
os.path.join(dist_info_directory, dist_infos[0]),
|
||||
metadata_directory)
|
||||
metadata_directory,
|
||||
)
|
||||
shutil.rmtree(dist_info_directory, ignore_errors=True)
|
||||
|
||||
return dist_infos[0]
|
||||
|
||||
def _build_with_temp_dir(self, setup_command, result_extension,
|
||||
result_directory, config_settings):
|
||||
def _build_with_temp_dir(
|
||||
self, setup_command, result_extension,
|
||||
result_directory, config_settings,
|
||||
):
|
||||
config_settings = self._fix_config(config_settings)
|
||||
result_directory = os.path.abspath(result_directory)
|
||||
|
||||
# Build in a temporary directory, then copy to the target.
|
||||
os.makedirs(result_directory, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir:
|
||||
sys.argv = (sys.argv[:1] + setup_command +
|
||||
['--dist-dir', tmp_dist_dir] +
|
||||
config_settings["--global-option"])
|
||||
sys.argv = (
|
||||
sys.argv[:1] + setup_command +
|
||||
['--dist-dir', tmp_dist_dir] +
|
||||
config_settings['--global-option']
|
||||
)
|
||||
with no_install_setup_requires():
|
||||
self.run_setup()
|
||||
|
||||
result_basename = _file_with_extension(
|
||||
tmp_dist_dir, result_extension)
|
||||
tmp_dist_dir, result_extension,
|
||||
)
|
||||
result_path = os.path.join(result_directory, result_basename)
|
||||
if os.path.exists(result_path):
|
||||
# os.rename will fail overwriting on non-Unix.
|
||||
|
|
@ -216,15 +234,21 @@ class _BuildMetaBackend(object):
|
|||
|
||||
return result_basename
|
||||
|
||||
def build_wheel(self, wheel_directory, config_settings=None,
|
||||
metadata_directory=None):
|
||||
return self._build_with_temp_dir(['bdist_wheel'], '.whl',
|
||||
wheel_directory, config_settings)
|
||||
def build_wheel(
|
||||
self, wheel_directory, config_settings=None,
|
||||
metadata_directory=None,
|
||||
):
|
||||
return self._build_with_temp_dir(
|
||||
['bdist_wheel'], '.whl',
|
||||
wheel_directory, config_settings,
|
||||
)
|
||||
|
||||
def build_sdist(self, sdist_directory, config_settings=None):
|
||||
return self._build_with_temp_dir(['sdist', '--formats', 'gztar'],
|
||||
'.tar.gz', sdist_directory,
|
||||
config_settings)
|
||||
return self._build_with_temp_dir(
|
||||
['sdist', '--formats', 'gztar'],
|
||||
'.tar.gz', sdist_directory,
|
||||
config_settings,
|
||||
)
|
||||
|
||||
|
||||
class _BuildMetaLegacyBackend(_BuildMetaBackend):
|
||||
|
|
@ -238,6 +262,7 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend):
|
|||
packaging mechanism,
|
||||
and will eventually be removed.
|
||||
"""
|
||||
|
||||
def run_setup(self, setup_script='setup.py'):
|
||||
# In order to maintain compatibility with scripts assuming that
|
||||
# the setup.py script is in a directory on the PYTHONPATH, inject
|
||||
|
|
@ -255,8 +280,7 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend):
|
|||
sys.argv[0] = setup_script
|
||||
|
||||
try:
|
||||
super(_BuildMetaLegacyBackend,
|
||||
self).run_setup(setup_script=setup_script)
|
||||
super().run_setup(setup_script=setup_script)
|
||||
finally:
|
||||
# While PEP 517 frontends should be calling each hook in a fresh
|
||||
# subprocess according to the standard (and thus it should not be
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
from distutils.command.bdist import bdist
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
from distutils.command.bdist import bdist
|
||||
|
||||
if 'egg' not in bdist.format_commands:
|
||||
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
|
||||
bdist.format_command['egg'] = ('bdist_egg', 'Python .egg file')
|
||||
bdist.format_commands.append('egg')
|
||||
|
||||
del bdist, sys
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
from distutils.errors import DistutilsOptionError
|
||||
from __future__ import annotations
|
||||
|
||||
from setuptools.command.setopt import edit_config, option_base, config_file
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from setuptools.command.setopt import config_file
|
||||
from setuptools.command.setopt import edit_config
|
||||
from setuptools.command.setopt import option_base
|
||||
|
||||
|
||||
def shquote(arg):
|
||||
"""Quote an argument for later parsing by shlex.split()"""
|
||||
for c in '"', "'", "\\", "#":
|
||||
for c in '"', "'", '\\', '#':
|
||||
if c in arg:
|
||||
return repr(arg)
|
||||
if arg.split() != [arg]:
|
||||
|
|
@ -16,7 +19,7 @@ def shquote(arg):
|
|||
class alias(option_base):
|
||||
"""Define a shortcut that invokes one or more commands"""
|
||||
|
||||
description = "define a shortcut to invoke one or more commands"
|
||||
description = 'define a shortcut to invoke one or more commands'
|
||||
command_consumes_arguments = True
|
||||
|
||||
user_options = [
|
||||
|
|
@ -34,18 +37,18 @@ class alias(option_base):
|
|||
option_base.finalize_options(self)
|
||||
if self.remove and len(self.args) != 1:
|
||||
raise DistutilsOptionError(
|
||||
"Must specify exactly one argument (the alias name) when "
|
||||
"using --remove"
|
||||
'Must specify exactly one argument (the alias name) when '
|
||||
'using --remove',
|
||||
)
|
||||
|
||||
def run(self):
|
||||
aliases = self.distribution.get_option_dict('aliases')
|
||||
|
||||
if not self.args:
|
||||
print("Command Aliases")
|
||||
print("---------------")
|
||||
print('Command Aliases')
|
||||
print('---------------')
|
||||
for alias in aliases:
|
||||
print("setup.py alias", format_alias(alias, aliases))
|
||||
print('setup.py alias', format_alias(alias, aliases))
|
||||
return
|
||||
|
||||
elif len(self.args) == 1:
|
||||
|
|
@ -53,10 +56,10 @@ class alias(option_base):
|
|||
if self.remove:
|
||||
command = None
|
||||
elif alias in aliases:
|
||||
print("setup.py alias", format_alias(alias, aliases))
|
||||
print('setup.py alias', format_alias(alias, aliases))
|
||||
return
|
||||
else:
|
||||
print("No alias definition found for %r" % alias)
|
||||
print('No alias definition found for %r' % alias)
|
||||
return
|
||||
else:
|
||||
alias = self.args[0]
|
||||
|
|
|
|||
|
|
@ -1,25 +1,29 @@
|
|||
"""setuptools.command.bdist_egg
|
||||
|
||||
Build .egg distributions"""
|
||||
from __future__ import annotations
|
||||
|
||||
from distutils.dir_util import remove_tree, mkpath
|
||||
from distutils import log
|
||||
from types import CodeType
|
||||
import sys
|
||||
import marshal
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
import marshal
|
||||
from sysconfig import get_path
|
||||
from sysconfig import get_python_version
|
||||
from types import CodeType
|
||||
|
||||
from pkg_resources import get_build_platform, Distribution, ensure_directory
|
||||
from setuptools.extension import Library
|
||||
from distutils import log
|
||||
from distutils.dir_util import mkpath
|
||||
from distutils.dir_util import remove_tree
|
||||
from pkg_resources import Distribution
|
||||
from pkg_resources import ensure_directory
|
||||
from pkg_resources import get_build_platform
|
||||
from setuptools import Command
|
||||
|
||||
from sysconfig import get_path, get_python_version
|
||||
from setuptools.extension import Library
|
||||
|
||||
|
||||
def _get_purelib():
|
||||
return get_path("purelib")
|
||||
return get_path('purelib')
|
||||
|
||||
|
||||
def strip_module(filename):
|
||||
|
|
@ -60,23 +64,35 @@ class bdist_egg(Command):
|
|||
description = "create an \"egg\" distribution"
|
||||
|
||||
user_options = [
|
||||
('bdist-dir=', 'b',
|
||||
"temporary directory for creating the distribution"),
|
||||
('plat-name=', 'p', "platform name to embed in generated filenames "
|
||||
"(default: %s)" % get_build_platform()),
|
||||
('exclude-source-files', None,
|
||||
"remove all .py files from the generated egg"),
|
||||
('keep-temp', 'k',
|
||||
"keep the pseudo-installation tree around after " +
|
||||
"creating the distribution archive"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put final built distributions in"),
|
||||
('skip-build', None,
|
||||
"skip rebuilding everything (for testing/debugging)"),
|
||||
(
|
||||
'bdist-dir=', 'b',
|
||||
'temporary directory for creating the distribution',
|
||||
),
|
||||
(
|
||||
'plat-name=', 'p', 'platform name to embed in generated filenames '
|
||||
'(default: %s)' % get_build_platform(),
|
||||
),
|
||||
(
|
||||
'exclude-source-files', None,
|
||||
'remove all .py files from the generated egg',
|
||||
),
|
||||
(
|
||||
'keep-temp', 'k',
|
||||
'keep the pseudo-installation tree around after ' +
|
||||
'creating the distribution archive',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put final built distributions in',
|
||||
),
|
||||
(
|
||||
'skip-build', None,
|
||||
'skip rebuilding everything (for testing/debugging)',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = [
|
||||
'keep-temp', 'skip-build', 'exclude-source-files'
|
||||
'keep-temp', 'skip-build', 'exclude-source-files',
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
|
|
@ -89,7 +105,7 @@ class bdist_egg(Command):
|
|||
self.exclude_source_files = None
|
||||
|
||||
def finalize_options(self):
|
||||
ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
|
||||
ei_cmd = self.ei_cmd = self.get_finalized_command('egg_info')
|
||||
self.egg_info = ei_cmd.egg_info
|
||||
|
||||
if self.bdist_dir is None:
|
||||
|
|
@ -107,7 +123,7 @@ class bdist_egg(Command):
|
|||
basename = Distribution(
|
||||
None, None, ei_cmd.egg_name, ei_cmd.egg_version,
|
||||
get_python_version(),
|
||||
self.distribution.has_ext_modules() and self.plat_name
|
||||
self.distribution.has_ext_modules() and self.plat_name,
|
||||
).egg_name()
|
||||
|
||||
self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
|
||||
|
|
@ -125,14 +141,14 @@ class bdist_egg(Command):
|
|||
realpath = os.path.realpath(item[0])
|
||||
normalized = os.path.normcase(realpath)
|
||||
if normalized == site_packages or normalized.startswith(
|
||||
site_packages + os.sep
|
||||
site_packages + os.sep,
|
||||
):
|
||||
item = realpath[len(site_packages) + 1:], item[1]
|
||||
# XXX else: raise ???
|
||||
self.distribution.data_files.append(item)
|
||||
|
||||
try:
|
||||
log.info("installing package data to %s", self.bdist_dir)
|
||||
log.info('installing package data to %s', self.bdist_dir)
|
||||
self.call_command('install_data', force=0, root=None)
|
||||
finally:
|
||||
self.distribution.data_files = old
|
||||
|
|
@ -152,10 +168,10 @@ class bdist_egg(Command):
|
|||
|
||||
def run(self): # noqa: C901 # is too complex (14) # FIXME
|
||||
# Generate metadata first
|
||||
self.run_command("egg_info")
|
||||
self.run_command('egg_info')
|
||||
# We run install_lib before install_data, because some data hacks
|
||||
# pull their data path from the install_lib command.
|
||||
log.info("installing library code to %s", self.bdist_dir)
|
||||
log.info('installing library code to %s', self.bdist_dir)
|
||||
instcmd = self.get_finalized_command('install')
|
||||
old_root = instcmd.root
|
||||
instcmd.root = None
|
||||
|
|
@ -169,10 +185,12 @@ class bdist_egg(Command):
|
|||
to_compile = []
|
||||
for (p, ext_name) in enumerate(ext_outputs):
|
||||
filename, ext = os.path.splitext(ext_name)
|
||||
pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
|
||||
'.py')
|
||||
pyfile = os.path.join(
|
||||
self.bdist_dir, strip_module(filename) +
|
||||
'.py',
|
||||
)
|
||||
self.stubs.append(pyfile)
|
||||
log.info("creating stub loader for %s", ext_name)
|
||||
log.info('creating stub loader for %s', ext_name)
|
||||
if not self.dry_run:
|
||||
write_stub(os.path.basename(ext_name), pyfile)
|
||||
to_compile.append(pyfile)
|
||||
|
|
@ -189,56 +207,61 @@ class bdist_egg(Command):
|
|||
self.mkpath(egg_info)
|
||||
if self.distribution.scripts:
|
||||
script_dir = os.path.join(egg_info, 'scripts')
|
||||
log.info("installing scripts to %s", script_dir)
|
||||
self.call_command('install_scripts', install_dir=script_dir,
|
||||
no_ep=1)
|
||||
log.info('installing scripts to %s', script_dir)
|
||||
self.call_command(
|
||||
'install_scripts', install_dir=script_dir,
|
||||
no_ep=1,
|
||||
)
|
||||
|
||||
self.copy_metadata_to(egg_info)
|
||||
native_libs = os.path.join(egg_info, "native_libs.txt")
|
||||
native_libs = os.path.join(egg_info, 'native_libs.txt')
|
||||
if all_outputs:
|
||||
log.info("writing %s", native_libs)
|
||||
log.info('writing %s', native_libs)
|
||||
if not self.dry_run:
|
||||
ensure_directory(native_libs)
|
||||
libs_file = open(native_libs, 'wt')
|
||||
libs_file = open(native_libs, 'w')
|
||||
libs_file.write('\n'.join(all_outputs))
|
||||
libs_file.write('\n')
|
||||
libs_file.close()
|
||||
elif os.path.isfile(native_libs):
|
||||
log.info("removing %s", native_libs)
|
||||
log.info('removing %s', native_libs)
|
||||
if not self.dry_run:
|
||||
os.unlink(native_libs)
|
||||
|
||||
write_safety_flag(
|
||||
os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
|
||||
os.path.join(archive_root, 'EGG-INFO'), self.zip_safe(),
|
||||
)
|
||||
|
||||
if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
|
||||
log.warn(
|
||||
"WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
|
||||
"Use the install_requires/extras_require setup() args instead."
|
||||
'Use the install_requires/extras_require setup() args instead.',
|
||||
)
|
||||
|
||||
if self.exclude_source_files:
|
||||
self.zap_pyfiles()
|
||||
|
||||
# Make the archive
|
||||
make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
|
||||
dry_run=self.dry_run, mode=self.gen_header())
|
||||
make_zipfile(
|
||||
self.egg_output, archive_root, verbose=self.verbose,
|
||||
dry_run=self.dry_run, mode=self.gen_header(),
|
||||
)
|
||||
if not self.keep_temp:
|
||||
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
||||
|
||||
# Add to 'Distribution.dist_files' so that the "upload" command works
|
||||
getattr(self.distribution, 'dist_files', []).append(
|
||||
('bdist_egg', get_python_version(), self.egg_output))
|
||||
('bdist_egg', get_python_version(), self.egg_output),
|
||||
)
|
||||
|
||||
def zap_pyfiles(self):
|
||||
log.info("Removing .py files from temporary directory")
|
||||
log.info('Removing .py files from temporary directory')
|
||||
for base, dirs, files in walk_egg(self.bdist_dir):
|
||||
for name in files:
|
||||
path = os.path.join(base, name)
|
||||
|
||||
if name.endswith('.py'):
|
||||
log.debug("Deleting %s", path)
|
||||
log.debug('Deleting %s', path)
|
||||
os.unlink(path)
|
||||
|
||||
if base.endswith('__pycache__'):
|
||||
|
|
@ -247,10 +270,12 @@ class bdist_egg(Command):
|
|||
pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc'
|
||||
m = re.match(pattern, name)
|
||||
path_new = os.path.join(
|
||||
base, os.pardir, m.group('name') + '.pyc')
|
||||
base, os.pardir, m.group('name') + '.pyc',
|
||||
)
|
||||
log.info(
|
||||
"Renaming file from [%s] to [%s]"
|
||||
% (path_old, path_new))
|
||||
'Renaming file from [%s] to [%s]'
|
||||
% (path_old, path_new),
|
||||
)
|
||||
try:
|
||||
os.remove(path_new)
|
||||
except OSError:
|
||||
|
|
@ -261,14 +286,14 @@ class bdist_egg(Command):
|
|||
safe = getattr(self.distribution, 'zip_safe', None)
|
||||
if safe is not None:
|
||||
return safe
|
||||
log.warn("zip_safe flag not set; analyzing archive contents...")
|
||||
log.warn('zip_safe flag not set; analyzing archive contents...')
|
||||
return analyze_egg(self.bdist_dir, self.stubs)
|
||||
|
||||
def gen_header(self):
|
||||
return 'w'
|
||||
|
||||
def copy_metadata_to(self, target_dir):
|
||||
"Copy metadata (egg info) to the target_dir"
|
||||
'Copy metadata (egg info) to the target_dir'
|
||||
# normalize the path (so that a forward-slash in egg_info will
|
||||
# match using startswith below)
|
||||
norm_egg_info = os.path.normpath(self.egg_info)
|
||||
|
|
@ -291,8 +316,10 @@ class bdist_egg(Command):
|
|||
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
|
||||
all_outputs.append(paths[base] + filename)
|
||||
for filename in dirs:
|
||||
paths[os.path.join(base, filename)] = (paths[base] +
|
||||
filename + '/')
|
||||
paths[os.path.join(base, filename)] = (
|
||||
paths[base] +
|
||||
filename + '/'
|
||||
)
|
||||
|
||||
if self.distribution.has_ext_modules():
|
||||
build_cmd = self.get_finalized_command('build_ext')
|
||||
|
|
@ -318,8 +345,7 @@ def walk_egg(egg_dir):
|
|||
if 'EGG-INFO' in dirs:
|
||||
dirs.remove('EGG-INFO')
|
||||
yield base, dirs, files
|
||||
for bdf in walker:
|
||||
yield bdf
|
||||
yield from walker
|
||||
|
||||
|
||||
def analyze_egg(egg_dir, stubs):
|
||||
|
|
@ -348,7 +374,7 @@ def write_safety_flag(egg_dir, safe):
|
|||
if safe is None or bool(safe) != flag:
|
||||
os.unlink(fn)
|
||||
elif safe is not None and bool(safe) == flag:
|
||||
f = open(fn, 'wt')
|
||||
f = open(fn, 'w')
|
||||
f.write('\n')
|
||||
f.close()
|
||||
|
||||
|
|
@ -367,10 +393,7 @@ def scan_module(egg_dir, base, name, stubs):
|
|||
return True # Extension module
|
||||
pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
|
||||
module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
|
||||
if sys.version_info < (3, 7):
|
||||
skip = 12 # skip magic & date & file size
|
||||
else:
|
||||
skip = 16 # skip magic & reserved? & date & file size
|
||||
skip = 16 # skip magic & reserved? & date & file size
|
||||
f = open(filename, 'rb')
|
||||
f.read(skip)
|
||||
code = marshal.load(f)
|
||||
|
|
@ -379,51 +402,53 @@ def scan_module(egg_dir, base, name, stubs):
|
|||
symbols = dict.fromkeys(iter_symbols(code))
|
||||
for bad in ['__file__', '__path__']:
|
||||
if bad in symbols:
|
||||
log.warn("%s: module references %s", module, bad)
|
||||
log.warn('%s: module references %s', module, bad)
|
||||
safe = False
|
||||
if 'inspect' in symbols:
|
||||
for bad in [
|
||||
'getsource', 'getabsfile', 'getsourcefile', 'getfile'
|
||||
'getsourcelines', 'findsource', 'getcomments', 'getframeinfo',
|
||||
'getinnerframes', 'getouterframes', 'stack', 'trace'
|
||||
'getinnerframes', 'getouterframes', 'stack', 'trace',
|
||||
]:
|
||||
if bad in symbols:
|
||||
log.warn("%s: module MAY be using inspect.%s", module, bad)
|
||||
log.warn('%s: module MAY be using inspect.%s', module, bad)
|
||||
safe = False
|
||||
return safe
|
||||
|
||||
|
||||
def iter_symbols(code):
|
||||
"""Yield names and strings used by `code` and its nested code objects"""
|
||||
for name in code.co_names:
|
||||
yield name
|
||||
yield from code.co_names
|
||||
for const in code.co_consts:
|
||||
if isinstance(const, str):
|
||||
yield const
|
||||
elif isinstance(const, CodeType):
|
||||
for name in iter_symbols(const):
|
||||
yield name
|
||||
yield from iter_symbols(const)
|
||||
|
||||
|
||||
def can_scan():
|
||||
if not sys.platform.startswith('java') and sys.platform != 'cli':
|
||||
# CPython, PyPy, etc.
|
||||
return True
|
||||
log.warn("Unable to analyze compiled code on this platform.")
|
||||
log.warn("Please ask the author to include a 'zip_safe'"
|
||||
" setting (either True or False) in the package's setup.py")
|
||||
log.warn('Unable to analyze compiled code on this platform.')
|
||||
log.warn(
|
||||
"Please ask the author to include a 'zip_safe'"
|
||||
" setting (either True or False) in the package's setup.py",
|
||||
)
|
||||
|
||||
|
||||
# Attribute names of options for commands that might need to be convinced to
|
||||
# install to the egg build directory
|
||||
|
||||
INSTALL_DIRECTORY_ATTRS = [
|
||||
'install_lib', 'install_dir', 'install_data', 'install_base'
|
||||
'install_lib', 'install_dir', 'install_data', 'install_base',
|
||||
]
|
||||
|
||||
|
||||
def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True,
|
||||
mode='w'):
|
||||
def make_zipfile(
|
||||
zip_filename, base_dir, verbose=0, dry_run=0, compress=True,
|
||||
mode='w',
|
||||
):
|
||||
"""Create a zip file from all the files under 'base_dir'. The output
|
||||
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
|
||||
Python module (if available) or the InfoZIP "zip" utility (if installed
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import distutils.command.bdist_rpm as orig
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
|
||||
import distutils.command.bdist_rpm as orig
|
||||
from setuptools import SetuptoolsDeprecationWarning
|
||||
|
||||
|
||||
|
|
@ -15,8 +17,8 @@ class bdist_rpm(orig.bdist_rpm):
|
|||
|
||||
def run(self):
|
||||
warnings.warn(
|
||||
"bdist_rpm is deprecated and will be removed in a future "
|
||||
"version. Use bdist_wheel (wheel packages) instead.",
|
||||
'bdist_rpm is deprecated and will be removed in a future '
|
||||
'version. Use bdist_wheel (wheel packages) instead.',
|
||||
SetuptoolsDeprecationWarning,
|
||||
)
|
||||
|
||||
|
|
@ -29,11 +31,11 @@ class bdist_rpm(orig.bdist_rpm):
|
|||
spec = orig.bdist_rpm._make_spec_file(self)
|
||||
spec = [
|
||||
line.replace(
|
||||
"setup.py install ",
|
||||
"setup.py install --single-version-externally-managed "
|
||||
'setup.py install ',
|
||||
'setup.py install --single-version-externally-managed ',
|
||||
).replace(
|
||||
"%setup",
|
||||
"%setup -n %{name}-%{unmangled_version}"
|
||||
'%setup',
|
||||
'%setup -n %{name}-%{unmangled_version}',
|
||||
)
|
||||
for line in spec
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import distutils.command.build_clib as orig
|
||||
from distutils.errors import DistutilsSetupError
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsSetupError
|
||||
from setuptools.dep_util import newer_pairwise_group
|
||||
|
||||
|
||||
|
|
@ -27,7 +29,8 @@ class build_clib(orig.build_clib):
|
|||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % lib_name)
|
||||
'a list of source filenames' % lib_name,
|
||||
)
|
||||
sources = list(sources)
|
||||
|
||||
log.info("building '%s' library", lib_name)
|
||||
|
|
@ -40,7 +43,8 @@ class build_clib(orig.build_clib):
|
|||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'obj_deps' must be a dictionary of "
|
||||
"type 'source: list'" % lib_name)
|
||||
"type 'source: list'" % lib_name,
|
||||
)
|
||||
dependencies = []
|
||||
|
||||
# Get the global dependencies that are specified by the '' key.
|
||||
|
|
@ -50,7 +54,8 @@ class build_clib(orig.build_clib):
|
|||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'obj_deps' must be a dictionary of "
|
||||
"type 'source: list'" % lib_name)
|
||||
"type 'source: list'" % lib_name,
|
||||
)
|
||||
|
||||
# Build the list to be used by newer_pairwise_group
|
||||
# each source will be auto-added to its dependencies.
|
||||
|
|
@ -62,7 +67,8 @@ class build_clib(orig.build_clib):
|
|||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'obj_deps' must be a dictionary of "
|
||||
"type 'source: list'" % lib_name)
|
||||
"type 'source: list'" % lib_name,
|
||||
)
|
||||
src_deps.extend(extra_deps)
|
||||
dependencies.append(src_deps)
|
||||
|
||||
|
|
@ -72,8 +78,8 @@ class build_clib(orig.build_clib):
|
|||
)
|
||||
|
||||
if (
|
||||
newer_pairwise_group(dependencies, expected_objects)
|
||||
!= ([], [])
|
||||
newer_pairwise_group(dependencies, expected_objects) !=
|
||||
([], [])
|
||||
):
|
||||
# First, compile the source code to object files in the library
|
||||
# directory. (This should probably change to putting object
|
||||
|
|
@ -87,7 +93,7 @@ class build_clib(orig.build_clib):
|
|||
macros=macros,
|
||||
include_dirs=include_dirs,
|
||||
extra_postargs=cflags,
|
||||
debug=self.debug
|
||||
debug=self.debug,
|
||||
)
|
||||
|
||||
# Now "link" the object files together into a static library.
|
||||
|
|
@ -97,5 +103,5 @@ class build_clib(orig.build_clib):
|
|||
expected_objects,
|
||||
lib_name,
|
||||
output_dir=self.build_clib,
|
||||
debug=self.debug
|
||||
debug=self.debug,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import sys
|
||||
import itertools
|
||||
from importlib.machinery import EXTENSION_SUFFIXES
|
||||
from distutils.command.build_ext import build_ext as _du_build_ext
|
||||
from distutils.file_util import copy_file
|
||||
from distutils.ccompiler import new_compiler
|
||||
from distutils.sysconfig import customize_compiler, get_config_var
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils import log
|
||||
|
||||
from distutils import log
|
||||
from distutils.ccompiler import new_compiler
|
||||
from distutils.command.build_ext import build_ext as _du_build_ext
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils.file_util import copy_file
|
||||
from distutils.sysconfig import customize_compiler
|
||||
from distutils.sysconfig import get_config_var
|
||||
from setuptools.extension import Library
|
||||
|
||||
try:
|
||||
|
|
@ -21,12 +24,12 @@ except ImportError:
|
|||
_build_ext = _du_build_ext
|
||||
|
||||
# make sure _config_vars is initialized
|
||||
get_config_var("LDSHARED")
|
||||
get_config_var('LDSHARED')
|
||||
from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa
|
||||
|
||||
|
||||
def _customize_compiler_for_shlib(compiler):
|
||||
if sys.platform == "darwin":
|
||||
if sys.platform == 'darwin':
|
||||
# building .dylib requires additional compiler flags on OSX; here we
|
||||
# temporarily substitute the pyconfig.h variables so that distutils'
|
||||
# 'customize_compiler' uses them before we build the shared libraries.
|
||||
|
|
@ -34,9 +37,10 @@ def _customize_compiler_for_shlib(compiler):
|
|||
try:
|
||||
# XXX Help! I don't have any idea whether these are right...
|
||||
_CONFIG_VARS['LDSHARED'] = (
|
||||
"gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
|
||||
_CONFIG_VARS['CCSHARED'] = " -dynamiclib"
|
||||
_CONFIG_VARS['SO'] = ".dylib"
|
||||
'gcc -Wl,-x -dynamiclib -undefined dynamic_lookup'
|
||||
)
|
||||
_CONFIG_VARS['CCSHARED'] = ' -dynamiclib'
|
||||
_CONFIG_VARS['SO'] = '.dylib'
|
||||
customize_compiler(compiler)
|
||||
finally:
|
||||
_CONFIG_VARS.clear()
|
||||
|
|
@ -49,7 +53,7 @@ have_rtld = False
|
|||
use_stubs = False
|
||||
libtype = 'shared'
|
||||
|
||||
if sys.platform == "darwin":
|
||||
if sys.platform == 'darwin':
|
||||
use_stubs = True
|
||||
elif os.name != 'nt':
|
||||
try:
|
||||
|
|
@ -89,8 +93,10 @@ class build_ext(_build_ext):
|
|||
modpath = fullname.split('.')
|
||||
package = '.'.join(modpath[:-1])
|
||||
package_dir = build_py.get_package_dir(package)
|
||||
dest_filename = os.path.join(package_dir,
|
||||
os.path.basename(filename))
|
||||
dest_filename = os.path.join(
|
||||
package_dir,
|
||||
os.path.basename(filename),
|
||||
)
|
||||
src_filename = os.path.join(self.build_lib, filename)
|
||||
|
||||
# Always copy, even if source is older than destination, to ensure
|
||||
|
|
@ -98,7 +104,7 @@ class build_ext(_build_ext):
|
|||
# used.
|
||||
copy_file(
|
||||
src_filename, dest_filename, verbose=self.verbose,
|
||||
dry_run=self.dry_run
|
||||
dry_run=self.dry_run,
|
||||
)
|
||||
if ext._needs_stub:
|
||||
self.write_stub(package_dir or os.curdir, ext, True)
|
||||
|
|
@ -136,8 +142,10 @@ class build_ext(_build_ext):
|
|||
_build_ext.finalize_options(self)
|
||||
self.extensions = self.extensions or []
|
||||
self.check_extensions_list(self.extensions)
|
||||
self.shlibs = [ext for ext in self.extensions
|
||||
if isinstance(ext, Library)]
|
||||
self.shlibs = [
|
||||
ext for ext in self.extensions
|
||||
if isinstance(ext, Library)
|
||||
]
|
||||
if self.shlibs:
|
||||
self.setup_shlib_compiler()
|
||||
for ext in self.extensions:
|
||||
|
|
@ -163,7 +171,7 @@ class build_ext(_build_ext):
|
|||
|
||||
def setup_shlib_compiler(self):
|
||||
compiler = self.shlib_compiler = new_compiler(
|
||||
compiler=self.compiler, dry_run=self.dry_run, force=self.force
|
||||
compiler=self.compiler, dry_run=self.dry_run, force=self.force,
|
||||
)
|
||||
_customize_compiler_for_shlib(compiler)
|
||||
|
||||
|
|
@ -236,52 +244,60 @@ class build_ext(_build_ext):
|
|||
yield '.pyo'
|
||||
|
||||
def write_stub(self, output_dir, ext, compile=False):
|
||||
log.info("writing stub loader for %s to %s", ext._full_name,
|
||||
output_dir)
|
||||
stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +
|
||||
'.py')
|
||||
log.info(
|
||||
'writing stub loader for %s to %s', ext._full_name,
|
||||
output_dir,
|
||||
)
|
||||
stub_file = (
|
||||
os.path.join(output_dir, *ext._full_name.split('.')) +
|
||||
'.py'
|
||||
)
|
||||
if compile and os.path.exists(stub_file):
|
||||
raise DistutilsError(stub_file + " already exists! Please delete.")
|
||||
raise DistutilsError(stub_file + ' already exists! Please delete.')
|
||||
if not self.dry_run:
|
||||
f = open(stub_file, 'w')
|
||||
f.write(
|
||||
'\n'.join([
|
||||
"def __bootstrap__():",
|
||||
" global __bootstrap__, __file__, __loader__",
|
||||
" import sys, os, pkg_resources, importlib.util" +
|
||||
if_dl(", dl"),
|
||||
" __file__ = pkg_resources.resource_filename"
|
||||
"(__name__,%r)"
|
||||
'def __bootstrap__():',
|
||||
' global __bootstrap__, __file__, __loader__',
|
||||
' import sys, os, pkg_resources, importlib.util' +
|
||||
if_dl(', dl'),
|
||||
' __file__ = pkg_resources.resource_filename'
|
||||
'(__name__,%r)'
|
||||
% os.path.basename(ext._file_name),
|
||||
" del __bootstrap__",
|
||||
' del __bootstrap__',
|
||||
" if '__loader__' in globals():",
|
||||
" del __loader__",
|
||||
if_dl(" old_flags = sys.getdlopenflags()"),
|
||||
" old_dir = os.getcwd()",
|
||||
" try:",
|
||||
" os.chdir(os.path.dirname(__file__))",
|
||||
if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
|
||||
" spec = importlib.util.spec_from_file_location(",
|
||||
" __name__, __file__)",
|
||||
" mod = importlib.util.module_from_spec(spec)",
|
||||
" spec.loader.exec_module(mod)",
|
||||
" finally:",
|
||||
if_dl(" sys.setdlopenflags(old_flags)"),
|
||||
" os.chdir(old_dir)",
|
||||
"__bootstrap__()",
|
||||
"" # terminal \n
|
||||
])
|
||||
' del __loader__',
|
||||
if_dl(' old_flags = sys.getdlopenflags()'),
|
||||
' old_dir = os.getcwd()',
|
||||
' try:',
|
||||
' os.chdir(os.path.dirname(__file__))',
|
||||
if_dl(' sys.setdlopenflags(dl.RTLD_NOW)'),
|
||||
' spec = importlib.util.spec_from_file_location(',
|
||||
' __name__, __file__)',
|
||||
' mod = importlib.util.module_from_spec(spec)',
|
||||
' spec.loader.exec_module(mod)',
|
||||
' finally:',
|
||||
if_dl(' sys.setdlopenflags(old_flags)'),
|
||||
' os.chdir(old_dir)',
|
||||
'__bootstrap__()',
|
||||
'', # terminal \n
|
||||
]),
|
||||
)
|
||||
f.close()
|
||||
if compile:
|
||||
from distutils.util import byte_compile
|
||||
|
||||
byte_compile([stub_file], optimize=0,
|
||||
force=True, dry_run=self.dry_run)
|
||||
byte_compile(
|
||||
[stub_file], optimize=0,
|
||||
force=True, dry_run=self.dry_run,
|
||||
)
|
||||
optimize = self.get_finalized_command('install_lib').optimize
|
||||
if optimize > 0:
|
||||
byte_compile([stub_file], optimize=optimize,
|
||||
force=True, dry_run=self.dry_run)
|
||||
byte_compile(
|
||||
[stub_file], optimize=optimize,
|
||||
force=True, dry_run=self.dry_run,
|
||||
)
|
||||
if os.path.exists(stub_file) and not self.dry_run:
|
||||
os.unlink(stub_file)
|
||||
|
||||
|
|
@ -293,12 +309,13 @@ if use_stubs or os.name == 'nt':
|
|||
self, objects, output_libname, output_dir=None, libraries=None,
|
||||
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
|
||||
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
|
||||
target_lang=None):
|
||||
target_lang=None,
|
||||
):
|
||||
self.link(
|
||||
self.SHARED_LIBRARY, objects, output_libname,
|
||||
output_dir, libraries, library_dirs, runtime_library_dirs,
|
||||
export_symbols, debug, extra_preargs, extra_postargs,
|
||||
build_temp, target_lang
|
||||
build_temp, target_lang,
|
||||
)
|
||||
else:
|
||||
# Build static libraries everywhere else
|
||||
|
|
@ -308,7 +325,8 @@ else:
|
|||
self, objects, output_libname, output_dir=None, libraries=None,
|
||||
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
|
||||
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
|
||||
target_lang=None):
|
||||
target_lang=None,
|
||||
):
|
||||
# XXX we need to either disallow these attrs on Library instances,
|
||||
# or warn/abort here if set, or something...
|
||||
# libraries=None, library_dirs=None, runtime_library_dirs=None,
|
||||
|
|
@ -318,11 +336,11 @@ else:
|
|||
assert output_dir is None # distutils build_ext doesn't pass this
|
||||
output_dir, filename = os.path.split(output_libname)
|
||||
basename, ext = os.path.splitext(filename)
|
||||
if self.library_filename("x").startswith('lib'):
|
||||
if self.library_filename('x').startswith('lib'):
|
||||
# strip 'lib' prefix; this is kludgy if some platform uses
|
||||
# a different prefix
|
||||
basename = basename[3:]
|
||||
|
||||
self.create_static_lib(
|
||||
objects, basename, output_dir, debug, target_lang
|
||||
objects, basename, output_dir, debug, target_lang,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
from glob import glob
|
||||
from distutils.util import convert_path
|
||||
import distutils.command.build_py as orig
|
||||
import os
|
||||
from __future__ import annotations
|
||||
|
||||
import fnmatch
|
||||
import textwrap
|
||||
import io
|
||||
import distutils.errors
|
||||
import itertools
|
||||
import os
|
||||
import stat
|
||||
import textwrap
|
||||
from glob import glob
|
||||
|
||||
import distutils.command.build_py as orig
|
||||
import distutils.errors
|
||||
from distutils.util import convert_path
|
||||
from setuptools.extern.more_itertools import unique_everseen
|
||||
|
||||
|
||||
|
|
@ -50,7 +53,7 @@ class build_py(orig.build_py):
|
|||
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"lazily compute data files"
|
||||
'lazily compute data files'
|
||||
if attr == 'data_files':
|
||||
self.data_files = self._get_data_files()
|
||||
return self.data_files
|
||||
|
|
@ -155,14 +158,14 @@ class build_py(orig.build_py):
|
|||
else:
|
||||
return init_py
|
||||
|
||||
with io.open(init_py, 'rb') as f:
|
||||
with open(init_py, 'rb') as f:
|
||||
contents = f.read()
|
||||
if b'declare_namespace' not in contents:
|
||||
raise distutils.errors.DistutilsError(
|
||||
"Namespace package problem: %s is a namespace package, but "
|
||||
"its\n__init__.py does not call declare_namespace()! Please "
|
||||
'Namespace package problem: %s is a namespace package, but '
|
||||
'its\n__init__.py does not call declare_namespace()! Please '
|
||||
'fix it.\n(See the setuptools manual under '
|
||||
'"Namespace Packages" for details.)\n"' % (package,)
|
||||
'"Namespace Packages" for details.)\n"' % (package,),
|
||||
)
|
||||
return init_py
|
||||
|
||||
|
|
@ -225,7 +228,7 @@ def assert_relative(path):
|
|||
|
||||
setup() arguments must *always* be /-separated paths relative to the
|
||||
setup.py directory, *never* absolute paths.
|
||||
"""
|
||||
""",
|
||||
).lstrip()
|
||||
% path
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
from distutils.util import convert_path
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsError, DistutilsOptionError
|
||||
import os
|
||||
from __future__ import annotations
|
||||
|
||||
import glob
|
||||
import io
|
||||
import os
|
||||
|
||||
import pkg_resources
|
||||
from setuptools.command.easy_install import easy_install
|
||||
from setuptools import namespaces
|
||||
import setuptools
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.util import convert_path
|
||||
from setuptools import namespaces
|
||||
from setuptools.command.easy_install import easy_install
|
||||
|
||||
|
||||
class develop(namespaces.DevelopInstaller, easy_install):
|
||||
|
|
@ -17,8 +20,8 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
description = "install package in 'development mode'"
|
||||
|
||||
user_options = easy_install.user_options + [
|
||||
("uninstall", "u", "Uninstall this source package"),
|
||||
("egg-path=", None, "Set the path to be used in the .egg-link file"),
|
||||
('uninstall', 'u', 'Uninstall this source package'),
|
||||
('egg-path=', None, 'Set the path to be used in the .egg-link file'),
|
||||
]
|
||||
|
||||
boolean_options = easy_install.boolean_options + ['uninstall']
|
||||
|
|
@ -42,7 +45,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
self.always_copy_from = '.' # always copy eggs installed in curdir
|
||||
|
||||
def finalize_options(self):
|
||||
ei = self.get_finalized_command("egg_info")
|
||||
ei = self.get_finalized_command('egg_info')
|
||||
if ei.broken_egg_info:
|
||||
template = "Please rename %r to %r before using 'develop'"
|
||||
args = ei.egg_info, ei.broken_egg_info
|
||||
|
|
@ -63,12 +66,12 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
|
||||
target = pkg_resources.normalize_path(self.egg_base)
|
||||
egg_path = pkg_resources.normalize_path(
|
||||
os.path.join(self.install_dir, self.egg_path)
|
||||
os.path.join(self.install_dir, self.egg_path),
|
||||
)
|
||||
if egg_path != target:
|
||||
raise DistutilsOptionError(
|
||||
"--egg-path must be a relative path from the install"
|
||||
" directory to " + target
|
||||
'--egg-path must be a relative path from the install'
|
||||
' directory to ' + target,
|
||||
)
|
||||
|
||||
# Make a distribution for the package's source
|
||||
|
|
@ -95,12 +98,12 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
if path_to_setup != os.curdir:
|
||||
path_to_setup = '../' * (path_to_setup.count('/') + 1)
|
||||
resolved = pkg_resources.normalize_path(
|
||||
os.path.join(install_dir, egg_path, path_to_setup)
|
||||
os.path.join(install_dir, egg_path, path_to_setup),
|
||||
)
|
||||
if resolved != pkg_resources.normalize_path(os.curdir):
|
||||
raise DistutilsOptionError(
|
||||
"Can't get a consistent path to setup script from"
|
||||
" installation directory",
|
||||
' installation directory',
|
||||
resolved,
|
||||
pkg_resources.normalize_path(os.curdir),
|
||||
)
|
||||
|
|
@ -120,22 +123,22 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
self.install_namespaces()
|
||||
|
||||
# create an .egg-link in the installation dir, pointing to our egg
|
||||
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
|
||||
log.info('Creating %s (link to %s)', self.egg_link, self.egg_base)
|
||||
if not self.dry_run:
|
||||
with open(self.egg_link, "w") as f:
|
||||
f.write(self.egg_path + "\n" + self.setup_path)
|
||||
with open(self.egg_link, 'w') as f:
|
||||
f.write(self.egg_path + '\n' + self.setup_path)
|
||||
# postprocess the installed distro, fixing up .pth, installing scripts,
|
||||
# and handling requirements
|
||||
self.process_distribution(None, self.dist, not self.no_deps)
|
||||
|
||||
def uninstall_link(self):
|
||||
if os.path.exists(self.egg_link):
|
||||
log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
|
||||
log.info('Removing %s (link to %s)', self.egg_link, self.egg_base)
|
||||
egg_link_file = open(self.egg_link)
|
||||
contents = [line.rstrip() for line in egg_link_file]
|
||||
egg_link_file.close()
|
||||
if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
|
||||
log.warn("Link points to %s: uninstall aborted", contents)
|
||||
log.warn('Link points to %s: uninstall aborted', contents)
|
||||
return
|
||||
if not self.dry_run:
|
||||
os.unlink(self.egg_link)
|
||||
|
|
@ -143,7 +146,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
self.update_pth(self.dist) # remove any .pth link to us
|
||||
if self.distribution.scripts:
|
||||
# XXX should also check for entry point scripts!
|
||||
log.warn("Note: you must uninstall or replace scripts manually!")
|
||||
log.warn('Note: you must uninstall or replace scripts manually!')
|
||||
|
||||
def install_egg_scripts(self, dist):
|
||||
if dist is not self.dist:
|
||||
|
|
@ -159,7 +162,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
|
|||
for script_name in self.distribution.scripts or []:
|
||||
script_path = os.path.abspath(convert_path(script_name))
|
||||
script_name = os.path.basename(script_path)
|
||||
with io.open(script_path) as strm:
|
||||
with open(script_path) as strm:
|
||||
script_text = strm.read()
|
||||
self.install_script(dist, script_name, script_text, script_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
Create a dist_info directory
|
||||
As defined in the wheel specification
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils import log
|
||||
from distutils.core import Command
|
||||
|
||||
|
||||
class dist_info(Command):
|
||||
|
|
@ -14,8 +15,10 @@ class dist_info(Command):
|
|||
description = 'create a .dist-info directory'
|
||||
|
||||
user_options = [
|
||||
('egg-base=', 'e', "directory containing .egg-info directories"
|
||||
" (default: top of the source tree)"),
|
||||
(
|
||||
'egg-base=', 'e', 'directory containing .egg-info directories'
|
||||
' (default: top of the source tree)',
|
||||
),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
|
|
@ -30,7 +33,7 @@ class dist_info(Command):
|
|||
egg_info.finalize_options()
|
||||
egg_info.run()
|
||||
dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info'
|
||||
log.info("creating '{}'".format(os.path.abspath(dist_info_dir)))
|
||||
log.info(f"creating '{os.path.abspath(dist_info_dir)}'")
|
||||
|
||||
bdist_wheel = self.get_finalized_command('bdist_wheel')
|
||||
bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,35 +1,40 @@
|
|||
"""setuptools.command.egg_info
|
||||
|
||||
Create a distribution's .egg-info directory and contents"""
|
||||
from __future__ import annotations
|
||||
|
||||
from distutils.filelist import FileList as _FileList
|
||||
from distutils.errors import DistutilsInternalError
|
||||
from distutils.util import convert_path
|
||||
from distutils import log
|
||||
import distutils.errors
|
||||
import distutils.filelist
|
||||
import collections
|
||||
import functools
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import io
|
||||
import warnings
|
||||
import time
|
||||
import collections
|
||||
import warnings
|
||||
|
||||
import distutils.errors
|
||||
import distutils.filelist
|
||||
import setuptools.unicode_utils as unicode_utils
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsInternalError
|
||||
from distutils.filelist import FileList as _FileList
|
||||
from distutils.util import convert_path
|
||||
from pkg_resources import EntryPoint
|
||||
from pkg_resources import iter_entry_points
|
||||
from pkg_resources import parse_requirements
|
||||
from pkg_resources import parse_version
|
||||
from pkg_resources import safe_name
|
||||
from pkg_resources import safe_version
|
||||
from pkg_resources import to_filename
|
||||
from pkg_resources import yield_lines
|
||||
from setuptools import Command
|
||||
from setuptools import SetuptoolsDeprecationWarning
|
||||
from setuptools.command import bdist_egg
|
||||
from setuptools.command.sdist import sdist
|
||||
from setuptools.command.sdist import walk_revctrl
|
||||
from setuptools.command.setopt import edit_config
|
||||
from setuptools.command import bdist_egg
|
||||
from pkg_resources import (
|
||||
parse_requirements, safe_name, parse_version,
|
||||
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
|
||||
import setuptools.unicode_utils as unicode_utils
|
||||
from setuptools.glob import glob
|
||||
|
||||
from setuptools.extern import packaging
|
||||
from setuptools import SetuptoolsDeprecationWarning
|
||||
from setuptools.glob import glob
|
||||
|
||||
|
||||
def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME
|
||||
|
|
@ -45,7 +50,7 @@ def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME
|
|||
chunks = glob.split(os.path.sep)
|
||||
|
||||
sep = re.escape(os.sep)
|
||||
valid_char = '[^%s]' % (sep,)
|
||||
valid_char = '[^{}]'.format(sep)
|
||||
|
||||
for c, chunk in enumerate(chunks):
|
||||
last_chunk = c == len(chunks) - 1
|
||||
|
|
@ -57,7 +62,7 @@ def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME
|
|||
pat += '.*'
|
||||
else:
|
||||
# Match '(name/)*'
|
||||
pat += '(?:%s+%s)*' % (valid_char, sep)
|
||||
pat += '(?:{}+{})*'.format(valid_char, sep)
|
||||
continue # Break here as the whole path component has been handled
|
||||
|
||||
# Find any special characters in the remainder
|
||||
|
|
@ -99,7 +104,7 @@ def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME
|
|||
inner = inner[1:]
|
||||
|
||||
char_class += re.escape(inner)
|
||||
pat += '[%s]' % (char_class,)
|
||||
pat += '[{}]'.format(char_class)
|
||||
|
||||
# Skip to the end ]
|
||||
i = inner_i
|
||||
|
|
@ -141,7 +146,7 @@ class InfoCommon:
|
|||
if self.tag_build:
|
||||
version += self.tag_build
|
||||
if self.tag_date:
|
||||
version += time.strftime("-%Y%m%d")
|
||||
version += time.strftime('-%Y%m%d')
|
||||
return version
|
||||
vtags = property(tags)
|
||||
|
||||
|
|
@ -150,10 +155,12 @@ class egg_info(InfoCommon, Command):
|
|||
description = "create a distribution's .egg-info directory"
|
||||
|
||||
user_options = [
|
||||
('egg-base=', 'e', "directory containing .egg-info directories"
|
||||
" (default: top of the source tree)"),
|
||||
('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
|
||||
('tag-build=', 'b', "Specify explicit tag to add to version number"),
|
||||
(
|
||||
'egg-base=', 'e', 'directory containing .egg-info directories'
|
||||
' (default: top of the source tree)',
|
||||
),
|
||||
('tag-date', 'd', 'Add date stamp (e.g. 20050528) to version number'),
|
||||
('tag-build=', 'b', 'Specify explicit tag to add to version number'),
|
||||
('no-date', 'D', "Don't include date stamp [default]"),
|
||||
]
|
||||
|
||||
|
|
@ -206,15 +213,15 @@ class egg_info(InfoCommon, Command):
|
|||
try:
|
||||
is_version = isinstance(parsed_version, packaging.version.Version)
|
||||
spec = (
|
||||
"%s==%s" if is_version else "%s===%s"
|
||||
'%s==%s' if is_version else '%s===%s'
|
||||
)
|
||||
list(
|
||||
parse_requirements(spec % (self.egg_name, self.egg_version))
|
||||
parse_requirements(spec % (self.egg_name, self.egg_version)),
|
||||
)
|
||||
except ValueError as e:
|
||||
raise distutils.errors.DistutilsOptionError(
|
||||
"Invalid distribution name or version syntax: %s-%s" %
|
||||
(self.egg_name, self.egg_version)
|
||||
'Invalid distribution name or version syntax: %s-%s' %
|
||||
(self.egg_name, self.egg_version),
|
||||
) from e
|
||||
|
||||
if self.egg_base is None:
|
||||
|
|
@ -257,7 +264,7 @@ class egg_info(InfoCommon, Command):
|
|||
elif os.path.exists(filename):
|
||||
if data is None and not force:
|
||||
log.warn(
|
||||
"%s not set in setup(), but %s exists", what, filename
|
||||
'%s not set in setup(), but %s exists', what, filename,
|
||||
)
|
||||
return
|
||||
else:
|
||||
|
|
@ -269,8 +276,8 @@ class egg_info(InfoCommon, Command):
|
|||
`what` is used in a log message to identify what is being written
|
||||
to the file.
|
||||
"""
|
||||
log.info("writing %s to %s", what, filename)
|
||||
data = data.encode("utf-8")
|
||||
log.info('writing %s to %s', what, filename)
|
||||
data = data.encode('utf-8')
|
||||
if not self.dry_run:
|
||||
f = open(filename, 'wb')
|
||||
f.write(data)
|
||||
|
|
@ -278,7 +285,7 @@ class egg_info(InfoCommon, Command):
|
|||
|
||||
def delete_file(self, filename):
|
||||
"""Delete `filename` (if not a dry run) after announcing it"""
|
||||
log.info("deleting %s", filename)
|
||||
log.info('deleting %s', filename)
|
||||
if not self.dry_run:
|
||||
os.unlink(filename)
|
||||
|
||||
|
|
@ -292,7 +299,7 @@ class egg_info(InfoCommon, Command):
|
|||
writer(self, ep.name, os.path.join(self.egg_info, ep.name))
|
||||
|
||||
# Get rid of native_libs.txt if it was put there by older bdist_egg
|
||||
nl = os.path.join(self.egg_info, "native_libs.txt")
|
||||
nl = os.path.join(self.egg_info, 'native_libs.txt')
|
||||
if os.path.exists(nl):
|
||||
self.delete_file(nl)
|
||||
|
||||
|
|
@ -300,7 +307,7 @@ class egg_info(InfoCommon, Command):
|
|||
|
||||
def find_sources(self):
|
||||
"""Generate SOURCES.txt manifest file"""
|
||||
manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
|
||||
manifest_filename = os.path.join(self.egg_info, 'SOURCES.txt')
|
||||
mm = manifest_maker(self.distribution)
|
||||
mm.manifest = manifest_filename
|
||||
mm.run()
|
||||
|
|
@ -312,11 +319,11 @@ class egg_info(InfoCommon, Command):
|
|||
bei = os.path.join(self.egg_base, bei)
|
||||
if os.path.exists(bei):
|
||||
log.warn(
|
||||
"-" * 78 + '\n'
|
||||
'-' * 78 + '\n'
|
||||
"Note: Your current .egg-info directory has a '-' in its name;"
|
||||
'\nthis will not work correctly with "setup.py develop".\n\n'
|
||||
'Please rename %s to %s to correct this problem.\n' + '-' * 78,
|
||||
bei, self.egg_info
|
||||
bei, self.egg_info,
|
||||
)
|
||||
self.broken_egg_info = self.egg_info
|
||||
self.egg_info = bei # make it work for now
|
||||
|
|
@ -350,15 +357,15 @@ class FileList(_FileList):
|
|||
log_map = {
|
||||
'include': "warning: no files found matching '%s'",
|
||||
'exclude': (
|
||||
"warning: no previously-included files found "
|
||||
'warning: no previously-included files found '
|
||||
"matching '%s'"
|
||||
),
|
||||
'global-include': (
|
||||
"warning: no files found matching '%s' "
|
||||
"anywhere in distribution"
|
||||
'anywhere in distribution'
|
||||
),
|
||||
'global-exclude': (
|
||||
"warning: no previously-included files matching "
|
||||
'warning: no previously-included files matching '
|
||||
"'%s' found anywhere in distribution"
|
||||
),
|
||||
'recursive-include': (
|
||||
|
|
@ -366,7 +373,7 @@ class FileList(_FileList):
|
|||
"under directory '%s'"
|
||||
),
|
||||
'recursive-exclude': (
|
||||
"warning: no previously-included files matching "
|
||||
'warning: no previously-included files matching '
|
||||
"'%s' found under directory '%s'"
|
||||
),
|
||||
'graft': "warning: no directories found matching '%s'",
|
||||
|
|
@ -388,7 +395,7 @@ class FileList(_FileList):
|
|||
action_is_recursive = action.startswith('recursive-')
|
||||
if action in {'graft', 'prune'}:
|
||||
patterns = [dir_pattern]
|
||||
extra_log_args = (dir, ) if action_is_recursive else ()
|
||||
extra_log_args = (dir,) if action_is_recursive else ()
|
||||
log_tmpl = log_map[action]
|
||||
|
||||
self.debug_print(
|
||||
|
|
@ -396,7 +403,7 @@ class FileList(_FileList):
|
|||
[action] +
|
||||
([dir] if action_is_recursive else []) +
|
||||
patterns,
|
||||
)
|
||||
),
|
||||
)
|
||||
for pattern in patterns:
|
||||
if not process_action(pattern):
|
||||
|
|
@ -410,7 +417,7 @@ class FileList(_FileList):
|
|||
found = False
|
||||
for i in range(len(self.files) - 1, -1, -1):
|
||||
if predicate(self.files[i]):
|
||||
self.debug_print(" removing " + self.files[i])
|
||||
self.debug_print(' removing ' + self.files[i])
|
||||
del self.files[i]
|
||||
found = True
|
||||
return found
|
||||
|
|
@ -431,8 +438,10 @@ class FileList(_FileList):
|
|||
Include all files anywhere in 'dir/' that match the pattern.
|
||||
"""
|
||||
full_pattern = os.path.join(dir, '**', pattern)
|
||||
found = [f for f in glob(full_pattern, recursive=True)
|
||||
if not os.path.isdir(f)]
|
||||
found = [
|
||||
f for f in glob(full_pattern, recursive=True)
|
||||
if not os.path.isdir(f)
|
||||
]
|
||||
self.extend(found)
|
||||
return bool(found)
|
||||
|
||||
|
|
@ -508,7 +517,7 @@ class FileList(_FileList):
|
|||
return False
|
||||
|
||||
# Must ensure utf-8 encodability
|
||||
utf8_path = unicode_utils.try_encode(u_path, "utf-8")
|
||||
utf8_path = unicode_utils.try_encode(u_path, 'utf-8')
|
||||
if utf8_path is None:
|
||||
log.warn(enc_warn, path, 'utf-8')
|
||||
return False
|
||||
|
|
@ -523,7 +532,7 @@ class FileList(_FileList):
|
|||
|
||||
|
||||
class manifest_maker(sdist):
|
||||
template = "MANIFEST.in"
|
||||
template = 'MANIFEST.in'
|
||||
|
||||
def initialize_options(self):
|
||||
self.use_defaults = 1
|
||||
|
|
@ -572,7 +581,7 @@ class manifest_maker(sdist):
|
|||
"""
|
||||
suppress missing-file warnings from sdist
|
||||
"""
|
||||
return re.match(r"standard file .*not found", msg)
|
||||
return re.match(r'standard file .*not found', msg)
|
||||
|
||||
def add_defaults(self):
|
||||
sdist.add_defaults(self)
|
||||
|
|
@ -584,10 +593,10 @@ class manifest_maker(sdist):
|
|||
elif os.path.exists(self.manifest):
|
||||
self.read_manifest()
|
||||
|
||||
if os.path.exists("setup.py"):
|
||||
if os.path.exists('setup.py'):
|
||||
# setup.py should be included by default, even if it's not
|
||||
# the script called to create the sdist
|
||||
self.filelist.append("setup.py")
|
||||
self.filelist.append('setup.py')
|
||||
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
self.filelist.graft(ei_cmd.egg_info)
|
||||
|
|
@ -605,25 +614,27 @@ class manifest_maker(sdist):
|
|||
self.filelist.prune(build.build_base)
|
||||
self.filelist.prune(base_dir)
|
||||
sep = re.escape(os.sep)
|
||||
self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
|
||||
is_regex=1)
|
||||
self.filelist.exclude_pattern(
|
||||
r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
|
||||
is_regex=1,
|
||||
)
|
||||
|
||||
|
||||
def write_file(filename, contents):
|
||||
"""Create a file with the specified name and write 'contents' (a
|
||||
sequence of strings without line terminators) to it.
|
||||
"""
|
||||
contents = "\n".join(contents)
|
||||
contents = '\n'.join(contents)
|
||||
|
||||
# assuming the contents has been vetted for utf-8 encoding
|
||||
contents = contents.encode("utf-8")
|
||||
contents = contents.encode('utf-8')
|
||||
|
||||
with open(filename, "wb") as f: # always write POSIX-style manifest
|
||||
with open(filename, 'wb') as f: # always write POSIX-style manifest
|
||||
f.write(contents)
|
||||
|
||||
|
||||
def write_pkg_info(cmd, basename, filename):
|
||||
log.info("writing %s", filename)
|
||||
log.info('writing %s', filename)
|
||||
if not cmd.dry_run:
|
||||
metadata = cmd.distribution.metadata
|
||||
metadata.version, oldver = cmd.egg_version, metadata.version
|
||||
|
|
@ -645,7 +656,7 @@ def warn_depends_obsolete(cmd, basename, filename):
|
|||
if os.path.exists(filename):
|
||||
log.warn(
|
||||
"WARNING: 'depends.txt' is not used by setuptools 0.6!\n"
|
||||
"Use the install_requires/extras_require setup() args instead."
|
||||
'Use the install_requires/extras_require setup() args instead.',
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -666,13 +677,13 @@ def write_requirements(cmd, basename, filename):
|
|||
for extra in sorted(extras_require):
|
||||
data.write('\n[{extra}]\n'.format(**vars()))
|
||||
_write_requirements(data, extras_require[extra])
|
||||
cmd.write_or_delete_file("requirements", filename, data.getvalue())
|
||||
cmd.write_or_delete_file('requirements', filename, data.getvalue())
|
||||
|
||||
|
||||
def write_setup_requirements(cmd, basename, filename):
|
||||
data = io.StringIO()
|
||||
_write_requirements(data, cmd.distribution.setup_requires)
|
||||
cmd.write_or_delete_file("setup-requirements", filename, data.getvalue())
|
||||
cmd.write_or_delete_file('setup-requirements', filename, data.getvalue())
|
||||
|
||||
|
||||
def write_toplevel_names(cmd, basename, filename):
|
||||
|
|
@ -680,9 +691,9 @@ def write_toplevel_names(cmd, basename, filename):
|
|||
[
|
||||
k.split('.', 1)[0]
|
||||
for k in cmd.distribution.iter_distribution_names()
|
||||
]
|
||||
],
|
||||
)
|
||||
cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n')
|
||||
cmd.write_file('top-level names', filename, '\n'.join(sorted(pkgs)) + '\n')
|
||||
|
||||
|
||||
def overwrite_arg(cmd, basename, filename):
|
||||
|
|
@ -708,7 +719,7 @@ def write_entries(cmd, basename, filename):
|
|||
if not isinstance(contents, str):
|
||||
contents = EntryPoint.parse_group(section, contents)
|
||||
contents = '\n'.join(sorted(map(str, contents.values())))
|
||||
data.append('[%s]\n%s\n\n' % (section, contents))
|
||||
data.append('[{}]\n{}\n\n'.format(section, contents))
|
||||
data = ''.join(data)
|
||||
|
||||
cmd.write_or_delete_file('entry points', filename, data, True)
|
||||
|
|
@ -720,11 +731,12 @@ def get_pkg_info_revision():
|
|||
a subversion revision.
|
||||
"""
|
||||
warnings.warn(
|
||||
"get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
|
||||
'get_pkg_info_revision is deprecated.', EggInfoDeprecationWarning,
|
||||
)
|
||||
if os.path.exists('PKG-INFO'):
|
||||
with io.open('PKG-INFO') as f:
|
||||
with open('PKG-INFO') as f:
|
||||
for line in f:
|
||||
match = re.match(r"Version:.*-r(\d+)\s*$", line)
|
||||
match = re.match(r'Version:.*-r(\d+)\s*$', line)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
return 0
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
from distutils.errors import DistutilsArgError
|
||||
import inspect
|
||||
import glob
|
||||
import warnings
|
||||
import platform
|
||||
import distutils.command.install as orig
|
||||
from __future__ import annotations
|
||||
|
||||
import glob
|
||||
import inspect
|
||||
import platform
|
||||
import warnings
|
||||
|
||||
import distutils.command.install as orig
|
||||
import setuptools
|
||||
from distutils.errors import DistutilsArgError
|
||||
|
||||
# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for
|
||||
# now. See https://github.com/pypa/setuptools/issues/199/
|
||||
|
|
@ -16,9 +18,11 @@ class install(orig.install):
|
|||
"""Use easy_install to install the package, w/dependencies"""
|
||||
|
||||
user_options = orig.install.user_options + [
|
||||
('old-and-unmanageable', None, "Try not to use this!"),
|
||||
('single-version-externally-managed', None,
|
||||
"used by system package builders to create 'flat' eggs"),
|
||||
('old-and-unmanageable', None, 'Try not to use this!'),
|
||||
(
|
||||
'single-version-externally-managed', None,
|
||||
"used by system package builders to create 'flat' eggs",
|
||||
),
|
||||
]
|
||||
boolean_options = orig.install.boolean_options + [
|
||||
'old-and-unmanageable', 'single-version-externally-managed',
|
||||
|
|
@ -41,8 +45,8 @@ class install(orig.install):
|
|||
elif self.single_version_externally_managed:
|
||||
if not self.root and not self.record:
|
||||
raise DistutilsArgError(
|
||||
"You must specify --record or --root when building system"
|
||||
" packages"
|
||||
'You must specify --record or --root when building system'
|
||||
' packages',
|
||||
)
|
||||
|
||||
def handle_extra_path(self):
|
||||
|
|
@ -78,10 +82,10 @@ class install(orig.install):
|
|||
is unavailable. Return False otherwise.
|
||||
"""
|
||||
if run_frame is None:
|
||||
msg = "Call stack not available. bdist_* commands may fail."
|
||||
msg = 'Call stack not available. bdist_* commands may fail.'
|
||||
warnings.warn(msg)
|
||||
if platform.python_implementation() == 'IronPython':
|
||||
msg = "For best results, pass -X:Frames to enable call stack."
|
||||
msg = 'For best results, pass -X:Frames to enable call stack.'
|
||||
warnings.warn(msg)
|
||||
return True
|
||||
res = inspect.getouterframes(run_frame)[2]
|
||||
|
|
@ -89,8 +93,8 @@ class install(orig.install):
|
|||
info = inspect.getframeinfo(caller)
|
||||
caller_module = caller.f_globals.get('__name__', '')
|
||||
return (
|
||||
caller_module == 'distutils.dist'
|
||||
and info.function == 'run_commands'
|
||||
caller_module == 'distutils.dist' and
|
||||
info.function == 'run_commands'
|
||||
)
|
||||
|
||||
def do_egg_install(self):
|
||||
|
|
@ -98,7 +102,7 @@ class install(orig.install):
|
|||
easy_install = self.distribution.get_command_class('easy_install')
|
||||
|
||||
cmd = easy_install(
|
||||
self.distribution, args="x", root=self.root, record=self.record,
|
||||
self.distribution, args='x', root=self.root, record=self.record,
|
||||
)
|
||||
cmd.ensure_finalized() # finalize before bdist_egg munges install cmd
|
||||
cmd.always_copy_from = '.' # make sure local-dir eggs get installed
|
||||
|
|
|
|||
|
|
@ -1,30 +1,35 @@
|
|||
from distutils import log, dir_util
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
import pkg_resources
|
||||
from distutils import dir_util
|
||||
from distutils import log
|
||||
from setuptools import Command
|
||||
from setuptools import namespaces
|
||||
from setuptools.archive_util import unpack_archive
|
||||
import pkg_resources
|
||||
|
||||
|
||||
class install_egg_info(namespaces.Installer, Command):
|
||||
"""Install an .egg-info directory for the package"""
|
||||
|
||||
description = "Install an .egg-info directory for the package"
|
||||
description = 'Install an .egg-info directory for the package'
|
||||
|
||||
user_options = [
|
||||
('install-dir=', 'd', "directory to install to"),
|
||||
('install-dir=', 'd', 'directory to install to'),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.install_dir = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('install_lib',
|
||||
('install_dir', 'install_dir'))
|
||||
ei_cmd = self.get_finalized_command("egg_info")
|
||||
self.set_undefined_options(
|
||||
'install_lib',
|
||||
('install_dir', 'install_dir'),
|
||||
)
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
basename = pkg_resources.Distribution(
|
||||
None, None, ei_cmd.egg_name, ei_cmd.egg_version
|
||||
None, None, ei_cmd.egg_name, ei_cmd.egg_version,
|
||||
).egg_name() + '.egg-info'
|
||||
self.source = ei_cmd.egg_info
|
||||
self.target = os.path.join(self.install_dir, basename)
|
||||
|
|
@ -35,11 +40,11 @@ class install_egg_info(namespaces.Installer, Command):
|
|||
if os.path.isdir(self.target) and not os.path.islink(self.target):
|
||||
dir_util.remove_tree(self.target, dry_run=self.dry_run)
|
||||
elif os.path.exists(self.target):
|
||||
self.execute(os.unlink, (self.target,), "Removing " + self.target)
|
||||
self.execute(os.unlink, (self.target,), 'Removing ' + self.target)
|
||||
if not self.dry_run:
|
||||
pkg_resources.ensure_directory(self.target)
|
||||
self.execute(
|
||||
self.copytree, (), "Copying %s to %s" % (self.source, self.target)
|
||||
self.copytree, (), 'Copying {} to {}'.format(self.source, self.target),
|
||||
)
|
||||
self.install_namespaces()
|
||||
|
||||
|
|
@ -56,7 +61,7 @@ class install_egg_info(namespaces.Installer, Command):
|
|||
if src.startswith(skip) or '/' + skip in src:
|
||||
return None
|
||||
self.outputs.append(dst)
|
||||
log.debug("Copying %s to %s", src, dst)
|
||||
log.debug('Copying %s to %s', src, dst)
|
||||
return dst
|
||||
|
||||
unpack_archive(self.source, self.target, skimmer)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
from itertools import product, starmap
|
||||
from itertools import product
|
||||
from itertools import starmap
|
||||
|
||||
import distutils.command.install_lib as orig
|
||||
|
||||
|
||||
|
|
@ -78,7 +82,8 @@ class install_lib(orig.install_lib):
|
|||
return
|
||||
|
||||
base = os.path.join(
|
||||
'__pycache__', '__init__.' + sys.implementation.cache_tag)
|
||||
'__pycache__', '__init__.' + sys.implementation.cache_tag,
|
||||
)
|
||||
yield base + '.pyc'
|
||||
yield base + '.pyo'
|
||||
yield base + '.opt-1.pyc'
|
||||
|
|
@ -86,7 +91,7 @@ class install_lib(orig.install_lib):
|
|||
|
||||
def copy_tree(
|
||||
self, infile, outfile,
|
||||
preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
|
||||
preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1,
|
||||
):
|
||||
assert preserve_mode and preserve_times and not preserve_symlinks
|
||||
exclude = self.get_exclusions()
|
||||
|
|
@ -103,11 +108,13 @@ class install_lib(orig.install_lib):
|
|||
|
||||
def pf(src, dst):
|
||||
if dst in exclude:
|
||||
log.warn("Skipping installation of %s (namespace package)",
|
||||
dst)
|
||||
log.warn(
|
||||
'Skipping installation of %s (namespace package)',
|
||||
dst,
|
||||
)
|
||||
return False
|
||||
|
||||
log.info("copying %s -> %s", src, os.path.dirname(dst))
|
||||
log.info('copying %s -> %s', src, os.path.dirname(dst))
|
||||
outfiles.append(dst)
|
||||
return dst
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
from distutils import log
|
||||
import distutils.command.install_scripts as orig
|
||||
from distutils.errors import DistutilsModuleError
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pkg_resources import Distribution, PathMetadata, ensure_directory
|
||||
import distutils.command.install_scripts as orig
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsModuleError
|
||||
from pkg_resources import Distribution
|
||||
from pkg_resources import ensure_directory
|
||||
from pkg_resources import PathMetadata
|
||||
|
||||
|
||||
class install_scripts(orig.install_scripts):
|
||||
|
|
@ -17,7 +21,7 @@ class install_scripts(orig.install_scripts):
|
|||
def run(self):
|
||||
import setuptools.command.easy_install as ei
|
||||
|
||||
self.run_command("egg_info")
|
||||
self.run_command('egg_info')
|
||||
if self.distribution.scripts:
|
||||
orig.install_scripts.run(self) # run first to set up self.outfiles
|
||||
else:
|
||||
|
|
@ -26,7 +30,7 @@ class install_scripts(orig.install_scripts):
|
|||
# don't install entry point scripts into .egg file!
|
||||
return
|
||||
|
||||
ei_cmd = self.get_finalized_command("egg_info")
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
dist = Distribution(
|
||||
ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info),
|
||||
ei_cmd.egg_name, ei_cmd.egg_version,
|
||||
|
|
@ -34,13 +38,13 @@ class install_scripts(orig.install_scripts):
|
|||
bs_cmd = self.get_finalized_command('build_scripts')
|
||||
exec_param = getattr(bs_cmd, 'executable', None)
|
||||
try:
|
||||
bw_cmd = self.get_finalized_command("bdist_wininst")
|
||||
bw_cmd = self.get_finalized_command('bdist_wininst')
|
||||
is_wininst = getattr(bw_cmd, '_is_running', False)
|
||||
except (ImportError, DistutilsModuleError):
|
||||
is_wininst = False
|
||||
writer = ei.ScriptWriter
|
||||
if is_wininst:
|
||||
exec_param = "python.exe"
|
||||
exec_param = 'python.exe'
|
||||
writer = ei.WindowsScriptWriter
|
||||
if exec_param == sys.executable:
|
||||
# In case the path to the Python executable contains a space, wrap
|
||||
|
|
@ -52,18 +56,18 @@ class install_scripts(orig.install_scripts):
|
|||
for args in writer.get_args(dist, cmd.as_header()):
|
||||
self.write_script(*args)
|
||||
|
||||
def write_script(self, script_name, contents, mode="t", *ignored):
|
||||
def write_script(self, script_name, contents, mode='t', *ignored):
|
||||
"""Write an executable file to the scripts directory"""
|
||||
from setuptools.command.easy_install import chmod, current_umask
|
||||
|
||||
log.info("Installing %s script to %s", script_name, self.install_dir)
|
||||
log.info('Installing %s script to %s', script_name, self.install_dir)
|
||||
target = os.path.join(self.install_dir, script_name)
|
||||
self.outfiles.append(target)
|
||||
|
||||
mask = current_umask()
|
||||
if not self.dry_run:
|
||||
ensure_directory(target)
|
||||
f = open(target, "w" + mode)
|
||||
f = open(target, 'w' + mode)
|
||||
f.write(contents)
|
||||
f.close()
|
||||
chmod(target, 0o777 - mask)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from glob import glob
|
||||
from distutils.util import convert_path
|
||||
|
||||
from distutils.command import sdist
|
||||
from distutils.util import convert_path
|
||||
|
||||
|
||||
class sdist_add_defaults:
|
||||
|
|
@ -65,8 +68,10 @@ class sdist_add_defaults:
|
|||
break
|
||||
|
||||
if not got_it:
|
||||
self.warn("standard file not found: should have one of " +
|
||||
', '.join(alts))
|
||||
self.warn(
|
||||
'standard file not found: should have one of ' +
|
||||
', '.join(alts),
|
||||
)
|
||||
else:
|
||||
if self._cs_path_exists(fn):
|
||||
self.filelist.append(fn)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from distutils import log
|
||||
import distutils.command.register as orig
|
||||
from __future__ import annotations
|
||||
|
||||
import distutils.command.register as orig
|
||||
from distutils import log
|
||||
from setuptools.errors import RemovedCommandError
|
||||
|
||||
|
||||
|
|
@ -9,10 +10,10 @@ class register(orig.register):
|
|||
|
||||
def run(self):
|
||||
msg = (
|
||||
"The register command has been removed, use twine to upload "
|
||||
+ "instead (https://pypi.org/p/twine)"
|
||||
'The register command has been removed, use twine to upload ' +
|
||||
'instead (https://pypi.org/p/twine)'
|
||||
)
|
||||
|
||||
self.announce("ERROR: " + msg, log.ERROR)
|
||||
self.announce('ERROR: ' + msg, log.ERROR)
|
||||
|
||||
raise RemovedCommandError(msg)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,22 @@
|
|||
from distutils.util import convert_path
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.util import convert_path
|
||||
from setuptools import Command
|
||||
|
||||
|
||||
class rotate(Command):
|
||||
"""Delete older distributions"""
|
||||
|
||||
description = "delete older distributions, keeping N newest files"
|
||||
description = 'delete older distributions, keeping N newest files'
|
||||
user_options = [
|
||||
('match=', 'm', "patterns to match (required)"),
|
||||
('dist-dir=', 'd', "directory where the distributions are"),
|
||||
('keep=', 'k', "number of matching distributions to keep"),
|
||||
('match=', 'm', 'patterns to match (required)'),
|
||||
('dist-dir=', 'd', 'directory where the distributions are'),
|
||||
('keep=', 'k', 'number of matching distributions to keep'),
|
||||
]
|
||||
|
||||
boolean_options = []
|
||||
|
|
@ -27,15 +29,15 @@ class rotate(Command):
|
|||
def finalize_options(self):
|
||||
if self.match is None:
|
||||
raise DistutilsOptionError(
|
||||
"Must specify one or more (comma-separated) match patterns "
|
||||
"(e.g. '.zip' or '.egg')"
|
||||
'Must specify one or more (comma-separated) match patterns '
|
||||
"(e.g. '.zip' or '.egg')",
|
||||
)
|
||||
if self.keep is None:
|
||||
raise DistutilsOptionError("Must specify number of files to keep")
|
||||
raise DistutilsOptionError('Must specify number of files to keep')
|
||||
try:
|
||||
self.keep = int(self.keep)
|
||||
except ValueError as e:
|
||||
raise DistutilsOptionError("--keep must be an integer") from e
|
||||
raise DistutilsOptionError('--keep must be an integer') from e
|
||||
if isinstance(self.match, str):
|
||||
self.match = [
|
||||
convert_path(p.strip()) for p in self.match.split(',')
|
||||
|
|
@ -43,7 +45,7 @@ class rotate(Command):
|
|||
self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
|
||||
|
||||
def run(self):
|
||||
self.run_command("egg_info")
|
||||
self.run_command('egg_info')
|
||||
from glob import glob
|
||||
|
||||
for pattern in self.match:
|
||||
|
|
@ -53,10 +55,10 @@ class rotate(Command):
|
|||
files.sort()
|
||||
files.reverse()
|
||||
|
||||
log.info("%d file(s) matching %s", len(files), pattern)
|
||||
log.info('%d file(s) matching %s', len(files), pattern)
|
||||
files = files[self.keep:]
|
||||
for (t, f) in files:
|
||||
log.info("Deleting %s", f)
|
||||
log.info('Deleting %s', f)
|
||||
if not self.dry_run:
|
||||
if os.path.isdir(f):
|
||||
shutil.rmtree(f)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
from setuptools.command.setopt import edit_config, option_base
|
||||
from __future__ import annotations
|
||||
|
||||
from setuptools.command.setopt import edit_config
|
||||
from setuptools.command.setopt import option_base
|
||||
|
||||
|
||||
class saveopts(option_base):
|
||||
"""Save command-line options to a file"""
|
||||
|
||||
description = "save supplied options to setup.cfg or other config file"
|
||||
description = 'save supplied options to setup.cfg or other config file'
|
||||
|
||||
def run(self):
|
||||
dist = self.distribution
|
||||
|
|
@ -16,7 +19,7 @@ class saveopts(option_base):
|
|||
continue # don't save our own options!
|
||||
|
||||
for opt, (src, val) in dist.get_option_dict(cmd).items():
|
||||
if src == "command line":
|
||||
if src == 'command line':
|
||||
settings.setdefault(cmd, {})[opt] = val
|
||||
|
||||
edit_config(self.filename, settings, self.dry_run)
|
||||
|
|
|
|||
|
|
@ -1,42 +1,49 @@
|
|||
from distutils import log
|
||||
import distutils.command.sdist as orig
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import io
|
||||
import contextlib
|
||||
|
||||
import distutils.command.sdist as orig
|
||||
import pkg_resources
|
||||
from distutils import log
|
||||
|
||||
from .py36compat import sdist_add_defaults
|
||||
|
||||
import pkg_resources
|
||||
|
||||
_default_revctrl = list
|
||||
|
||||
|
||||
def walk_revctrl(dirname=''):
|
||||
"""Find all files under revision control"""
|
||||
for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
|
||||
for item in ep.load()(dirname):
|
||||
yield item
|
||||
yield from ep.load()(dirname)
|
||||
|
||||
|
||||
class sdist(sdist_add_defaults, orig.sdist):
|
||||
"""Smart sdist that finds anything supported by revision control"""
|
||||
|
||||
user_options = [
|
||||
('formats=', None,
|
||||
"formats for source distribution (comma-separated list)"),
|
||||
('keep-temp', 'k',
|
||||
"keep the distribution tree around after creating " +
|
||||
"archive file(s)"),
|
||||
('dist-dir=', 'd',
|
||||
"directory to put the source distribution archive(s) in "
|
||||
"[default: dist]"),
|
||||
(
|
||||
'formats=', None,
|
||||
'formats for source distribution (comma-separated list)',
|
||||
),
|
||||
(
|
||||
'keep-temp', 'k',
|
||||
'keep the distribution tree around after creating ' +
|
||||
'archive file(s)',
|
||||
),
|
||||
(
|
||||
'dist-dir=', 'd',
|
||||
'directory to put the source distribution archive(s) in '
|
||||
'[default: dist]',
|
||||
),
|
||||
]
|
||||
|
||||
negative_opt = {}
|
||||
|
||||
README_EXTENSIONS = ['', '.rst', '.txt', '.md']
|
||||
READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
|
||||
READMES = tuple(f'README{ext}' for ext in README_EXTENSIONS)
|
||||
|
||||
def run(self):
|
||||
self.run_command('egg_info')
|
||||
|
|
@ -132,7 +139,7 @@ class sdist(sdist_add_defaults, orig.sdist):
|
|||
try:
|
||||
super()._add_defaults_data_files()
|
||||
except TypeError:
|
||||
log.warn("data_files contains unexpected objects")
|
||||
log.warn('data_files contains unexpected objects')
|
||||
|
||||
def check_readme(self):
|
||||
for f in self.READMES:
|
||||
|
|
@ -140,8 +147,8 @@ class sdist(sdist_add_defaults, orig.sdist):
|
|||
return
|
||||
else:
|
||||
self.warn(
|
||||
"standard file not found: should have one of " +
|
||||
', '.join(self.READMES)
|
||||
'standard file not found: should have one of ' +
|
||||
', '.join(self.READMES),
|
||||
)
|
||||
|
||||
def make_release_tree(self, base_dir, files):
|
||||
|
|
@ -162,10 +169,12 @@ class sdist(sdist_add_defaults, orig.sdist):
|
|||
if not os.path.isfile(self.manifest):
|
||||
return False
|
||||
|
||||
with io.open(self.manifest, 'rb') as fp:
|
||||
with open(self.manifest, 'rb') as fp:
|
||||
first_line = fp.readline()
|
||||
return (first_line !=
|
||||
'# file GENERATED by distutils, do NOT edit\n'.encode())
|
||||
return (
|
||||
first_line !=
|
||||
b'# file GENERATED by distutils, do NOT edit\n'
|
||||
)
|
||||
|
||||
def read_manifest(self):
|
||||
"""Read the manifest file (named by 'self.manifest') and use it to
|
||||
|
|
@ -179,7 +188,7 @@ class sdist(sdist_add_defaults, orig.sdist):
|
|||
try:
|
||||
line = line.decode('UTF-8')
|
||||
except UnicodeDecodeError:
|
||||
log.warn("%r not UTF-8 decodable -- skipping" % line)
|
||||
log.warn('%r not UTF-8 decodable -- skipping' % line)
|
||||
continue
|
||||
# ignore comments and blank lines
|
||||
line = line.strip()
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
from distutils.util import convert_path
|
||||
from __future__ import annotations
|
||||
|
||||
import configparser
|
||||
import os
|
||||
|
||||
import distutils
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsOptionError
|
||||
import distutils
|
||||
import os
|
||||
import configparser
|
||||
|
||||
from distutils.util import convert_path
|
||||
from setuptools import Command
|
||||
|
||||
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
|
||||
|
||||
|
||||
def config_file(kind="local"):
|
||||
def config_file(kind='local'):
|
||||
"""Get the filename of the distutils, local, global, or per-user config
|
||||
|
||||
`kind` must be one of "local", "global", or "user"
|
||||
|
|
@ -19,13 +21,13 @@ def config_file(kind="local"):
|
|||
return 'setup.cfg'
|
||||
if kind == 'global':
|
||||
return os.path.join(
|
||||
os.path.dirname(distutils.__file__), 'distutils.cfg'
|
||||
os.path.dirname(distutils.__file__), 'distutils.cfg',
|
||||
)
|
||||
if kind == 'user':
|
||||
dot = os.name == 'posix' and '.' or ''
|
||||
return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
|
||||
return os.path.expanduser(convert_path('~/%spydistutils.cfg' % dot))
|
||||
raise ValueError(
|
||||
"config_file() type must be 'local', 'global', or 'user'", kind
|
||||
"config_file() type must be 'local', 'global', or 'user'", kind,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -37,37 +39,39 @@ def edit_config(filename, settings, dry_run=False):
|
|||
while a dictionary lists settings to be changed or deleted in that section.
|
||||
A setting of ``None`` means to delete that setting.
|
||||
"""
|
||||
log.debug("Reading configuration from %s", filename)
|
||||
log.debug('Reading configuration from %s', filename)
|
||||
opts = configparser.RawConfigParser()
|
||||
opts.optionxform = lambda x: x
|
||||
opts.read([filename])
|
||||
for section, options in settings.items():
|
||||
if options is None:
|
||||
log.info("Deleting section [%s] from %s", section, filename)
|
||||
log.info('Deleting section [%s] from %s', section, filename)
|
||||
opts.remove_section(section)
|
||||
else:
|
||||
if not opts.has_section(section):
|
||||
log.debug("Adding new section [%s] to %s", section, filename)
|
||||
log.debug('Adding new section [%s] to %s', section, filename)
|
||||
opts.add_section(section)
|
||||
for option, value in options.items():
|
||||
if value is None:
|
||||
log.debug(
|
||||
"Deleting %s.%s from %s",
|
||||
section, option, filename
|
||||
'Deleting %s.%s from %s',
|
||||
section, option, filename,
|
||||
)
|
||||
opts.remove_option(section, option)
|
||||
if not opts.options(section):
|
||||
log.info("Deleting empty [%s] section from %s",
|
||||
section, filename)
|
||||
log.info(
|
||||
'Deleting empty [%s] section from %s',
|
||||
section, filename,
|
||||
)
|
||||
opts.remove_section(section)
|
||||
else:
|
||||
log.debug(
|
||||
"Setting %s.%s to %r in %s",
|
||||
section, option, value, filename
|
||||
'Setting %s.%s to %r in %s',
|
||||
section, option, value, filename,
|
||||
)
|
||||
opts.set(section, option, value)
|
||||
|
||||
log.info("Writing %s", filename)
|
||||
log.info('Writing %s', filename)
|
||||
if not dry_run:
|
||||
with open(filename, 'w') as f:
|
||||
opts.write(f)
|
||||
|
|
@ -77,12 +81,18 @@ class option_base(Command):
|
|||
"""Abstract base class for commands that mess with config files"""
|
||||
|
||||
user_options = [
|
||||
('global-config', 'g',
|
||||
"save options to the site-wide distutils.cfg file"),
|
||||
('user-config', 'u',
|
||||
"save options to the current user's pydistutils.cfg file"),
|
||||
('filename=', 'f',
|
||||
"configuration file to use (default=setup.cfg)"),
|
||||
(
|
||||
'global-config', 'g',
|
||||
'save options to the site-wide distutils.cfg file',
|
||||
),
|
||||
(
|
||||
'user-config', 'u',
|
||||
"save options to the current user's pydistutils.cfg file",
|
||||
),
|
||||
(
|
||||
'filename=', 'f',
|
||||
'configuration file to use (default=setup.cfg)',
|
||||
),
|
||||
]
|
||||
|
||||
boolean_options = [
|
||||
|
|
@ -106,8 +116,8 @@ class option_base(Command):
|
|||
filenames.append(config_file('local'))
|
||||
if len(filenames) > 1:
|
||||
raise DistutilsOptionError(
|
||||
"Must specify only one configuration file option",
|
||||
filenames
|
||||
'Must specify only one configuration file option',
|
||||
filenames,
|
||||
)
|
||||
self.filename, = filenames
|
||||
|
||||
|
|
@ -115,7 +125,7 @@ class option_base(Command):
|
|||
class setopt(option_base):
|
||||
"""Save command-line options to a file"""
|
||||
|
||||
description = "set an option in setup.cfg or another config file"
|
||||
description = 'set an option in setup.cfg or another config file'
|
||||
|
||||
user_options = [
|
||||
('command=', 'c', 'command to set an option for'),
|
||||
|
|
@ -136,14 +146,14 @@ class setopt(option_base):
|
|||
def finalize_options(self):
|
||||
option_base.finalize_options(self)
|
||||
if self.command is None or self.option is None:
|
||||
raise DistutilsOptionError("Must specify --command *and* --option")
|
||||
raise DistutilsOptionError('Must specify --command *and* --option')
|
||||
if self.set_value is None and not self.remove:
|
||||
raise DistutilsOptionError("Must specify --set-value or --remove")
|
||||
raise DistutilsOptionError('Must specify --set-value or --remove')
|
||||
|
||||
def run(self):
|
||||
edit_config(
|
||||
self.filename, {
|
||||
self.command: {self.option.replace('-', '_'): self.set_value}
|
||||
self.command: {self.option.replace('-', '_'): self.set_value},
|
||||
},
|
||||
self.dry_run
|
||||
self.dry_run,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
import os
|
||||
import operator
|
||||
import sys
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import itertools
|
||||
import operator
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from distutils.errors import DistutilsError, DistutilsOptionError
|
||||
from distutils import log
|
||||
from unittest import TestLoader
|
||||
|
||||
from pkg_resources import (
|
||||
resource_listdir,
|
||||
resource_exists,
|
||||
normalize_path,
|
||||
working_set,
|
||||
evaluate_marker,
|
||||
add_activation_listener,
|
||||
require,
|
||||
EntryPoint,
|
||||
)
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from pkg_resources import add_activation_listener
|
||||
from pkg_resources import EntryPoint
|
||||
from pkg_resources import evaluate_marker
|
||||
from pkg_resources import normalize_path
|
||||
from pkg_resources import require
|
||||
from pkg_resources import resource_exists
|
||||
from pkg_resources import resource_listdir
|
||||
from pkg_resources import working_set
|
||||
from setuptools import Command
|
||||
from setuptools.extern.more_itertools import unique_everseen
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ class ScanningLoader(TestLoader):
|
|||
tests = []
|
||||
tests.append(TestLoader.loadTestsFromModule(self, module))
|
||||
|
||||
if hasattr(module, "additional_tests"):
|
||||
if hasattr(module, 'additional_tests'):
|
||||
tests.append(module.additional_tests())
|
||||
|
||||
if hasattr(module, '__path__'):
|
||||
|
|
@ -75,7 +76,7 @@ class NonDataProperty:
|
|||
class test(Command):
|
||||
"""Command to run unit tests after in-place build"""
|
||||
|
||||
description = "run unit tests after in-place build (deprecated)"
|
||||
description = 'run unit tests after in-place build (deprecated)'
|
||||
|
||||
user_options = [
|
||||
('test-module=', 'm', "Run 'test_suite' in specified module"),
|
||||
|
|
@ -84,7 +85,7 @@ class test(Command):
|
|||
's',
|
||||
"Run single test, case or suite (e.g. 'module.test_suite')",
|
||||
),
|
||||
('test-runner=', 'r', "Test runner to use"),
|
||||
('test-runner=', 'r', 'Test runner to use'),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
|
|
@ -96,19 +97,19 @@ class test(Command):
|
|||
def finalize_options(self):
|
||||
|
||||
if self.test_suite and self.test_module:
|
||||
msg = "You may specify a module or a suite, but not both"
|
||||
msg = 'You may specify a module or a suite, but not both'
|
||||
raise DistutilsOptionError(msg)
|
||||
|
||||
if self.test_suite is None:
|
||||
if self.test_module is None:
|
||||
self.test_suite = self.distribution.test_suite
|
||||
else:
|
||||
self.test_suite = self.test_module + ".test_suite"
|
||||
self.test_suite = self.test_module + '.test_suite'
|
||||
|
||||
if self.test_loader is None:
|
||||
self.test_loader = getattr(self.distribution, 'test_loader', None)
|
||||
if self.test_loader is None:
|
||||
self.test_loader = "setuptools.command.test:ScanningLoader"
|
||||
self.test_loader = 'setuptools.command.test:ScanningLoader'
|
||||
if self.test_runner is None:
|
||||
self.test_runner = getattr(self.distribution, 'test_runner', None)
|
||||
|
||||
|
|
@ -139,7 +140,7 @@ class test(Command):
|
|||
self.reinitialize_command('build_ext', inplace=1)
|
||||
self.run_command('build_ext')
|
||||
|
||||
ei_cmd = self.get_finalized_command("egg_info")
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
|
||||
old_path = sys.path[:]
|
||||
old_modules = sys.modules.copy()
|
||||
|
|
@ -149,7 +150,7 @@ class test(Command):
|
|||
sys.path.insert(0, project_path)
|
||||
working_set.__init__()
|
||||
add_activation_listener(lambda dist: dist.activate())
|
||||
require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
|
||||
require('{}=={}'.format(ei_cmd.egg_name, ei_cmd.egg_version))
|
||||
with self.paths_on_pythonpath([project_path]):
|
||||
yield
|
||||
finally:
|
||||
|
|
@ -201,10 +202,10 @@ class test(Command):
|
|||
|
||||
def run(self):
|
||||
self.announce(
|
||||
"WARNING: Testing via this command is deprecated and will be "
|
||||
"removed in a future version. Users looking for a generic test "
|
||||
"entry point independent of test runner are encouraged to use "
|
||||
"tox.",
|
||||
'WARNING: Testing via this command is deprecated and will be '
|
||||
'removed in a future version. Users looking for a generic test '
|
||||
'entry point independent of test runner are encouraged to use '
|
||||
'tox.',
|
||||
log.WARN,
|
||||
)
|
||||
|
||||
|
|
@ -248,5 +249,5 @@ class test(Command):
|
|||
"""
|
||||
if val is None:
|
||||
return
|
||||
parsed = EntryPoint.parse("x=" + val)
|
||||
parsed = EntryPoint.parse('x=' + val)
|
||||
return parsed.resolve()()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from distutils import log
|
||||
from distutils.command import upload as orig
|
||||
|
||||
from setuptools.errors import RemovedCommandError
|
||||
|
||||
|
||||
|
|
@ -9,9 +10,9 @@ class upload(orig.upload):
|
|||
|
||||
def run(self):
|
||||
msg = (
|
||||
"The upload command has been removed, use twine to upload "
|
||||
+ "instead (https://pypi.org/p/twine)"
|
||||
'The upload command has been removed, use twine to upload ' +
|
||||
'instead (https://pypi.org/p/twine)'
|
||||
)
|
||||
|
||||
self.announce("ERROR: " + msg, log.ERROR)
|
||||
self.announce('ERROR: ' + msg, log.ERROR)
|
||||
raise RemovedCommandError(msg)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""upload_docs
|
||||
|
||||
Implements a Distutils 'upload_docs' subcommand (upload documentation to
|
||||
sites other than PyPi such as devpi).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from base64 import standard_b64encode
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsOptionError
|
||||
import os
|
||||
import socket
|
||||
import zipfile
|
||||
import tempfile
|
||||
import shutil
|
||||
import itertools
|
||||
import functools
|
||||
import http.client
|
||||
import itertools
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import tempfile
|
||||
import urllib.parse
|
||||
import zipfile
|
||||
from base64 import standard_b64encode
|
||||
|
||||
from distutils import log
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from pkg_resources import iter_entry_points
|
||||
|
||||
from .upload import upload
|
||||
|
||||
|
||||
|
|
@ -34,10 +35,14 @@ class upload_docs(upload):
|
|||
description = 'Upload documentation to sites other than PyPi such as devpi'
|
||||
|
||||
user_options = [
|
||||
('repository=', 'r',
|
||||
"url of repository [default: %s]" % upload.DEFAULT_REPOSITORY),
|
||||
('show-response', None,
|
||||
'display full response text from server'),
|
||||
(
|
||||
'repository=', 'r',
|
||||
'url of repository [default: %s]' % upload.DEFAULT_REPOSITORY,
|
||||
),
|
||||
(
|
||||
'show-response', None,
|
||||
'display full response text from server',
|
||||
),
|
||||
('upload-dir=', None, 'directory to upload'),
|
||||
]
|
||||
boolean_options = upload.boolean_options
|
||||
|
|
@ -67,11 +72,11 @@ class upload_docs(upload):
|
|||
self.ensure_dirname('upload_dir')
|
||||
self.target_dir = self.upload_dir
|
||||
if 'pypi.python.org' in self.repository:
|
||||
log.warn("Upload_docs command is deprecated for PyPi. Use RTD instead.")
|
||||
log.warn('Upload_docs command is deprecated for PyPi. Use RTD instead.')
|
||||
self.announce('Using upload directory %s' % self.target_dir)
|
||||
|
||||
def create_zipfile(self, filename):
|
||||
zip_file = zipfile.ZipFile(filename, "w")
|
||||
zip_file = zipfile.ZipFile(filename, 'w')
|
||||
try:
|
||||
self.mkpath(self.target_dir) # just in case
|
||||
for root, dirs, files in os.walk(self.target_dir):
|
||||
|
|
@ -93,7 +98,7 @@ class upload_docs(upload):
|
|||
|
||||
tmp_dir = tempfile.mkdtemp()
|
||||
name = self.distribution.metadata.get_name()
|
||||
zip_file = os.path.join(tmp_dir, "%s.zip" % name)
|
||||
zip_file = os.path.join(tmp_dir, '%s.zip' % name)
|
||||
try:
|
||||
self.create_zipfile(zip_file)
|
||||
self.upload_file(zip_file)
|
||||
|
|
@ -115,7 +120,7 @@ class upload_docs(upload):
|
|||
value = _encode(value)
|
||||
yield sep_boundary
|
||||
yield _encode(title)
|
||||
yield b"\n\n"
|
||||
yield b'\n\n'
|
||||
yield value
|
||||
if value and value[-1:] == b'\r':
|
||||
yield b'\n' # write an extra newline (lurve Macs)
|
||||
|
|
@ -128,7 +133,7 @@ class upload_docs(upload):
|
|||
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
sep_boundary = b'\n--' + boundary.encode('ascii')
|
||||
end_boundary = sep_boundary + b'--'
|
||||
end_items = end_boundary, b"\n",
|
||||
end_items = end_boundary, b'\n',
|
||||
builder = functools.partial(
|
||||
cls._build_part,
|
||||
sep_boundary=sep_boundary,
|
||||
|
|
@ -151,11 +156,11 @@ class upload_docs(upload):
|
|||
# set up the authentication
|
||||
credentials = _encode(self.username + ':' + self.password)
|
||||
credentials = standard_b64encode(credentials).decode('ascii')
|
||||
auth = "Basic " + credentials
|
||||
auth = 'Basic ' + credentials
|
||||
|
||||
body, ct = self._build_multipart(data)
|
||||
|
||||
msg = "Submitting documentation to %s" % (self.repository)
|
||||
msg = 'Submitting documentation to %s' % (self.repository)
|
||||
self.announce(msg, log.INFO)
|
||||
|
||||
# build the Request
|
||||
|
|
@ -169,25 +174,25 @@ class upload_docs(upload):
|
|||
elif schema == 'https':
|
||||
conn = http.client.HTTPSConnection(netloc)
|
||||
else:
|
||||
raise AssertionError("unsupported schema " + schema)
|
||||
raise AssertionError('unsupported schema ' + schema)
|
||||
|
||||
data = ''
|
||||
try:
|
||||
conn.connect()
|
||||
conn.putrequest("POST", url)
|
||||
conn.putrequest('POST', url)
|
||||
content_type = ct
|
||||
conn.putheader('Content-type', content_type)
|
||||
conn.putheader('Content-length', str(len(body)))
|
||||
conn.putheader('Authorization', auth)
|
||||
conn.endheaders()
|
||||
conn.send(body)
|
||||
except socket.error as e:
|
||||
except OSError as e:
|
||||
self.announce(str(e), log.ERROR)
|
||||
return
|
||||
|
||||
r = conn.getresponse()
|
||||
if r.status == 200:
|
||||
msg = 'Server response (%s): %s' % (r.status, r.reason)
|
||||
msg = 'Server response ({}): {}'.format(r.status, r.reason)
|
||||
self.announce(msg, log.INFO)
|
||||
elif r.status == 301:
|
||||
location = r.getheader('Location')
|
||||
|
|
@ -196,7 +201,7 @@ class upload_docs(upload):
|
|||
msg = 'Upload successful. Visit %s' % location
|
||||
self.announce(msg, log.INFO)
|
||||
else:
|
||||
msg = 'Upload failed (%s): %s' % (r.status, r.reason)
|
||||
msg = 'Upload failed ({}): {}'.format(r.status, r.reason)
|
||||
self.announce(msg, log.ERROR)
|
||||
if self.show_response:
|
||||
print('-' * 75, r.read(), '-' * 75)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,23 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import contextlib
|
||||
import functools
|
||||
import importlib
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
|
||||
import warnings
|
||||
import functools
|
||||
import importlib
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from functools import wraps
|
||||
from glob import iglob
|
||||
import contextlib
|
||||
|
||||
from distutils.errors import DistutilsOptionError, DistutilsFileError
|
||||
from setuptools.extern.packaging.version import LegacyVersion, parse
|
||||
from distutils.errors import DistutilsFileError
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from setuptools.extern.packaging.specifiers import SpecifierSet
|
||||
from setuptools.extern.packaging.version import LegacyVersion
|
||||
from setuptools.extern.packaging.version import parse
|
||||
|
||||
|
||||
class StaticModule:
|
||||
|
|
@ -41,7 +44,7 @@ class StaticModule:
|
|||
)
|
||||
except Exception as e:
|
||||
raise AttributeError(
|
||||
"{self.name} has no attribute {attr}".format(**locals())
|
||||
f'{self.name} has no attribute {attr}',
|
||||
) from e
|
||||
|
||||
|
||||
|
|
@ -93,7 +96,7 @@ def read_configuration(filepath, find_others=False, ignore_option_errors=False):
|
|||
_Distribution.parse_config_files(dist, filenames=filenames)
|
||||
|
||||
handlers = parse_configuration(
|
||||
dist, dist.command_options, ignore_option_errors=ignore_option_errors
|
||||
dist, dist.command_options, ignore_option_errors=ignore_option_errors,
|
||||
)
|
||||
|
||||
finally:
|
||||
|
|
@ -108,7 +111,7 @@ def _get_option(target_obj, key):
|
|||
the target object, either through a get_{key} method or
|
||||
from an attribute directly.
|
||||
"""
|
||||
getter_name = 'get_{key}'.format(**locals())
|
||||
getter_name = f'get_{key}'
|
||||
by_attribute = functools.partial(getattr, target_obj, key)
|
||||
getter = getattr(target_obj, getter_name, by_attribute)
|
||||
return getter()
|
||||
|
|
@ -196,7 +199,7 @@ class ConfigHandler:
|
|||
def parsers(self):
|
||||
"""Metadata item name to parser function mapping."""
|
||||
raise NotImplementedError(
|
||||
'%s must provide .parsers property' % self.__class__.__name__
|
||||
'%s must provide .parsers property' % self.__class__.__name__,
|
||||
)
|
||||
|
||||
def __setitem__(self, option_name, value):
|
||||
|
|
@ -275,9 +278,12 @@ class ConfigHandler:
|
|||
# Has globby characters?
|
||||
if any(char in value for char in glob_characters):
|
||||
# then expand the glob pattern while keeping paths *relative*:
|
||||
expanded_values.extend(sorted(
|
||||
os.path.relpath(path, os.getcwd())
|
||||
for path in iglob(os.path.abspath(value))))
|
||||
expanded_values.extend(
|
||||
sorted(
|
||||
os.path.relpath(path, os.getcwd())
|
||||
for path in iglob(os.path.abspath(value))
|
||||
),
|
||||
)
|
||||
|
||||
else:
|
||||
# take the value as-is:
|
||||
|
|
@ -298,7 +304,7 @@ class ConfigHandler:
|
|||
key, sep, val = line.partition(separator)
|
||||
if sep != separator:
|
||||
raise DistutilsOptionError(
|
||||
'Unable to parse option value to dict: %s' % value
|
||||
'Unable to parse option value to dict: %s' % value,
|
||||
)
|
||||
result[key.strip()] = val.strip()
|
||||
|
||||
|
|
@ -330,8 +336,8 @@ class ConfigHandler:
|
|||
exclude_directive = 'file:'
|
||||
if value.startswith(exclude_directive):
|
||||
raise ValueError(
|
||||
'Only strings are accepted for the {0} field, '
|
||||
'files are not accepted'.format(key)
|
||||
'Only strings are accepted for the {} field, '
|
||||
'files are not accepted'.format(key),
|
||||
)
|
||||
return value
|
||||
|
||||
|
|
@ -359,7 +365,7 @@ class ConfigHandler:
|
|||
if not value.startswith(include_directive):
|
||||
return value
|
||||
|
||||
spec = value[len(include_directive) :]
|
||||
spec = value[len(include_directive):]
|
||||
filepaths = (os.path.abspath(path.strip()) for path in spec.split(','))
|
||||
return '\n'.join(
|
||||
cls._read_file(path)
|
||||
|
|
@ -374,7 +380,7 @@ class ConfigHandler:
|
|||
|
||||
@staticmethod
|
||||
def _read_file(filepath):
|
||||
with io.open(filepath, encoding='utf-8') as f:
|
||||
with open(filepath, encoding='utf-8') as f:
|
||||
return f.read()
|
||||
|
||||
@classmethod
|
||||
|
|
@ -492,7 +498,7 @@ class ConfigHandler:
|
|||
if section_parser_method is None:
|
||||
raise DistutilsOptionError(
|
||||
'Unsupported distribution option section: [%s.%s]'
|
||||
% (self.section_prefix, section_name)
|
||||
% (self.section_prefix, section_name),
|
||||
)
|
||||
|
||||
section_parser_method(section_options)
|
||||
|
|
@ -531,10 +537,10 @@ class ConfigMetadataHandler(ConfigHandler):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self, target_obj, options, ignore_option_errors=False, package_dir=None
|
||||
self, target_obj, options, ignore_option_errors=False, package_dir=None,
|
||||
):
|
||||
super(ConfigMetadataHandler, self).__init__(
|
||||
target_obj, options, ignore_option_errors
|
||||
super().__init__(
|
||||
target_obj, options, ignore_option_errors,
|
||||
)
|
||||
self.package_dir = package_dir
|
||||
|
||||
|
|
@ -552,8 +558,8 @@ class ConfigMetadataHandler(ConfigHandler):
|
|||
'provides': parse_list,
|
||||
'requires': self._deprecated_config_handler(
|
||||
parse_list,
|
||||
"The requires parameter is deprecated, please use "
|
||||
"install_requires for runtime dependencies.",
|
||||
'The requires parameter is deprecated, please use '
|
||||
'install_requires for runtime dependencies.',
|
||||
DeprecationWarning,
|
||||
),
|
||||
'obsoletes': parse_list,
|
||||
|
|
@ -561,8 +567,8 @@ class ConfigMetadataHandler(ConfigHandler):
|
|||
'license': exclude_files_parser('license'),
|
||||
'license_file': self._deprecated_config_handler(
|
||||
exclude_files_parser('license_file'),
|
||||
"The license_file parameter is deprecated, "
|
||||
"use license_files instead.",
|
||||
'The license_file parameter is deprecated, '
|
||||
'use license_files instead.',
|
||||
DeprecationWarning,
|
||||
),
|
||||
'license_files': parse_list,
|
||||
|
|
@ -642,7 +648,7 @@ class ConfigOptionsHandler(ConfigHandler):
|
|||
def _parse_cmdclass(self, value):
|
||||
def resolve_class(qualified_class_name):
|
||||
idx = qualified_class_name.rfind('.')
|
||||
class_name = qualified_class_name[idx + 1 :]
|
||||
class_name = qualified_class_name[idx + 1:]
|
||||
pkg_name = qualified_class_name[:idx]
|
||||
|
||||
module = __import__(pkg_name)
|
||||
|
|
@ -667,7 +673,7 @@ class ConfigOptionsHandler(ConfigHandler):
|
|||
|
||||
# Read function arguments from a dedicated section.
|
||||
find_kwargs = self.parse_section_packages__find(
|
||||
self.sections.get('packages.find', {})
|
||||
self.sections.get('packages.find', {}),
|
||||
)
|
||||
|
||||
if findns:
|
||||
|
|
@ -688,9 +694,9 @@ class ConfigOptionsHandler(ConfigHandler):
|
|||
|
||||
valid_keys = ['where', 'include', 'exclude']
|
||||
|
||||
find_kwargs = dict(
|
||||
[(k, v) for k, v in section_data.items() if k in valid_keys and v]
|
||||
)
|
||||
find_kwargs = {
|
||||
k: v for k, v in section_data.items() if k in valid_keys and v
|
||||
}
|
||||
|
||||
where = find_kwargs.get('where')
|
||||
if where is not None:
|
||||
|
|
@ -737,7 +743,7 @@ class ConfigOptionsHandler(ConfigHandler):
|
|||
"""
|
||||
parse_list = partial(self._parse_list, separator=';')
|
||||
self['extras_require'] = self._parse_section_to_dict(
|
||||
section_options, parse_list
|
||||
section_options, parse_list,
|
||||
)
|
||||
|
||||
def parse_section_data_files(self, section_options):
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue