Change venv
This commit is contained in:
@@ -2,7 +2,11 @@ from distutils.command.bdist import bdist
|
||||
import sys
|
||||
|
||||
if 'egg' not in bdist.format_commands:
|
||||
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
|
||||
bdist.format_commands.append('egg')
|
||||
try:
|
||||
bdist.format_commands['egg'] = ('bdist_egg', "Python .egg file")
|
||||
except TypeError:
|
||||
# For backward compatibility with older distutils (stdlib)
|
||||
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
|
||||
bdist.format_commands.append('egg')
|
||||
|
||||
del bdist, sys
|
||||
|
@@ -11,9 +11,10 @@ import re
|
||||
import textwrap
|
||||
import marshal
|
||||
|
||||
from pkg_resources import get_build_platform, Distribution, ensure_directory
|
||||
from pkg_resources import get_build_platform, Distribution
|
||||
from setuptools.extension import Library
|
||||
from setuptools import Command
|
||||
from .._path import ensure_directory
|
||||
|
||||
from sysconfig import get_path, get_python_version
|
||||
|
||||
|
@@ -2,14 +2,16 @@ import os
|
||||
import sys
|
||||
import itertools
|
||||
from importlib.machinery import EXTENSION_SUFFIXES
|
||||
from importlib.util import cache_from_source as _compiled_file_name
|
||||
from typing import Dict, Iterator, List, Tuple
|
||||
|
||||
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 setuptools.extension import Library
|
||||
from setuptools.errors import BaseError
|
||||
from setuptools.extension import Extension, Library
|
||||
|
||||
try:
|
||||
# Attempt to use Cython for building extensions, if available
|
||||
@@ -73,6 +75,9 @@ def get_abi3_suffix():
|
||||
|
||||
|
||||
class build_ext(_build_ext):
|
||||
editable_mode: bool = False
|
||||
inplace: bool = False
|
||||
|
||||
def run(self):
|
||||
"""Build extensions in build directory, then copy if --inplace"""
|
||||
old_inplace, self.inplace = self.inplace, 0
|
||||
@@ -81,27 +86,62 @@ class build_ext(_build_ext):
|
||||
if old_inplace:
|
||||
self.copy_extensions_to_source()
|
||||
|
||||
def _get_inplace_equivalent(self, build_py, ext: Extension) -> Tuple[str, str]:
|
||||
fullname = self.get_ext_fullname(ext.name)
|
||||
filename = self.get_ext_filename(fullname)
|
||||
modpath = fullname.split('.')
|
||||
package = '.'.join(modpath[:-1])
|
||||
package_dir = build_py.get_package_dir(package)
|
||||
inplace_file = os.path.join(package_dir, os.path.basename(filename))
|
||||
regular_file = os.path.join(self.build_lib, filename)
|
||||
return (inplace_file, regular_file)
|
||||
|
||||
def copy_extensions_to_source(self):
|
||||
build_py = self.get_finalized_command('build_py')
|
||||
for ext in self.extensions:
|
||||
fullname = self.get_ext_fullname(ext.name)
|
||||
filename = self.get_ext_filename(fullname)
|
||||
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))
|
||||
src_filename = os.path.join(self.build_lib, filename)
|
||||
inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext)
|
||||
|
||||
# Always copy, even if source is older than destination, to ensure
|
||||
# that the right extensions for the current Python/platform are
|
||||
# used.
|
||||
copy_file(
|
||||
src_filename, dest_filename, verbose=self.verbose,
|
||||
dry_run=self.dry_run
|
||||
)
|
||||
if os.path.exists(regular_file) or not ext.optional:
|
||||
self.copy_file(regular_file, inplace_file, level=self.verbose)
|
||||
|
||||
if ext._needs_stub:
|
||||
self.write_stub(package_dir or os.curdir, ext, True)
|
||||
inplace_stub = self._get_equivalent_stub(ext, inplace_file)
|
||||
self._write_stub_file(inplace_stub, ext, compile=True)
|
||||
# Always compile stub and remove the original (leave the cache behind)
|
||||
# (this behaviour was observed in previous iterations of the code)
|
||||
|
||||
def _get_equivalent_stub(self, ext: Extension, output_file: str) -> str:
|
||||
dir_ = os.path.dirname(output_file)
|
||||
_, _, name = ext.name.rpartition(".")
|
||||
return f"{os.path.join(dir_, name)}.py"
|
||||
|
||||
def _get_output_mapping(self) -> Iterator[Tuple[str, str]]:
|
||||
if not self.inplace:
|
||||
return
|
||||
|
||||
build_py = self.get_finalized_command('build_py')
|
||||
opt = self.get_finalized_command('install_lib').optimize or ""
|
||||
|
||||
for ext in self.extensions:
|
||||
inplace_file, regular_file = self._get_inplace_equivalent(build_py, ext)
|
||||
yield (regular_file, inplace_file)
|
||||
|
||||
if ext._needs_stub:
|
||||
# This version of `build_ext` always builds artifacts in another dir,
|
||||
# when "inplace=True" is given it just copies them back.
|
||||
# This is done in the `copy_extensions_to_source` function, which
|
||||
# always compile stub files via `_compile_and_remove_stub`.
|
||||
# At the end of the process, a `.pyc` stub file is created without the
|
||||
# corresponding `.py`.
|
||||
|
||||
inplace_stub = self._get_equivalent_stub(ext, inplace_file)
|
||||
regular_stub = self._get_equivalent_stub(ext, regular_file)
|
||||
inplace_cache = _compiled_file_name(inplace_stub, optimization=opt)
|
||||
output_cache = _compiled_file_name(regular_stub, optimization=opt)
|
||||
yield (output_cache, inplace_cache)
|
||||
|
||||
def get_ext_filename(self, fullname):
|
||||
so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX')
|
||||
@@ -131,6 +171,7 @@ class build_ext(_build_ext):
|
||||
self.shlib_compiler = None
|
||||
self.shlibs = []
|
||||
self.ext_map = {}
|
||||
self.editable_mode = False
|
||||
|
||||
def finalize_options(self):
|
||||
_build_ext.finalize_options(self)
|
||||
@@ -161,6 +202,9 @@ class build_ext(_build_ext):
|
||||
if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
|
||||
ext.runtime_library_dirs.append(os.curdir)
|
||||
|
||||
if self.editable_mode:
|
||||
self.inplace = True
|
||||
|
||||
def setup_shlib_compiler(self):
|
||||
compiler = self.shlib_compiler = new_compiler(
|
||||
compiler=self.compiler, dry_run=self.dry_run, force=self.force
|
||||
@@ -201,8 +245,8 @@ class build_ext(_build_ext):
|
||||
self.compiler = self.shlib_compiler
|
||||
_build_ext.build_extension(self, ext)
|
||||
if ext._needs_stub:
|
||||
cmd = self.get_finalized_command('build_py').build_lib
|
||||
self.write_stub(cmd, ext)
|
||||
build_lib = self.get_finalized_command('build_py').build_lib
|
||||
self.write_stub(build_lib, ext)
|
||||
finally:
|
||||
self.compiler = _compiler
|
||||
|
||||
@@ -215,8 +259,15 @@ class build_ext(_build_ext):
|
||||
pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
|
||||
return any(pkg + libname in libnames for libname in ext.libraries)
|
||||
|
||||
def get_outputs(self):
|
||||
return _build_ext.get_outputs(self) + self.__get_stubs_outputs()
|
||||
def get_outputs(self) -> List[str]:
|
||||
if self.inplace:
|
||||
return list(self.get_output_mapping().keys())
|
||||
return sorted(_build_ext.get_outputs(self) + self.__get_stubs_outputs())
|
||||
|
||||
def get_output_mapping(self) -> Dict[str, str]:
|
||||
"""See :class:`setuptools.commands.build.SubCommand`"""
|
||||
mapping = self._get_output_mapping()
|
||||
return dict(sorted(mapping, key=lambda x: x[0]))
|
||||
|
||||
def __get_stubs_outputs(self):
|
||||
# assemble the base name for each extension that needs a stub
|
||||
@@ -236,12 +287,13 @@ 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')
|
||||
stub_file = os.path.join(output_dir, *ext._full_name.split('.')) + '.py'
|
||||
self._write_stub_file(stub_file, ext, compile)
|
||||
|
||||
def _write_stub_file(self, stub_file: str, ext: Extension, compile=False):
|
||||
log.info("writing stub loader for %s to %s", ext._full_name, stub_file)
|
||||
if compile and os.path.exists(stub_file):
|
||||
raise DistutilsError(stub_file + " already exists! Please delete.")
|
||||
raise BaseError(stub_file + " already exists! Please delete.")
|
||||
if not self.dry_run:
|
||||
f = open(stub_file, 'w')
|
||||
f.write(
|
||||
@@ -274,16 +326,19 @@ class build_ext(_build_ext):
|
||||
)
|
||||
f.close()
|
||||
if compile:
|
||||
from distutils.util import byte_compile
|
||||
self._compile_and_remove_stub(stub_file)
|
||||
|
||||
byte_compile([stub_file], optimize=0,
|
||||
def _compile_and_remove_stub(self, stub_file: str):
|
||||
from distutils.util import byte_compile
|
||||
|
||||
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)
|
||||
optimize = self.get_finalized_command('install_lib').optimize
|
||||
if optimize > 0:
|
||||
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)
|
||||
if os.path.exists(stub_file) and not self.dry_run:
|
||||
os.unlink(stub_file)
|
||||
|
||||
|
||||
if use_stubs or os.name == 'nt':
|
||||
|
@@ -1,3 +1,4 @@
|
||||
from functools import partial
|
||||
from glob import glob
|
||||
from distutils.util import convert_path
|
||||
import distutils.command.build_py as orig
|
||||
@@ -8,6 +9,11 @@ import io
|
||||
import distutils.errors
|
||||
import itertools
|
||||
import stat
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable, Iterator, List, Optional, Tuple
|
||||
|
||||
from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
|
||||
from setuptools.extern.more_itertools import unique_everseen
|
||||
|
||||
|
||||
@@ -24,6 +30,8 @@ class build_py(orig.build_py):
|
||||
Also, this version of the 'build_py' command allows you to specify both
|
||||
'py_modules' and 'packages' in the same setup operation.
|
||||
"""
|
||||
editable_mode: bool = False
|
||||
existing_egg_info_dir: Optional[str] = None #: Private API, internal use only.
|
||||
|
||||
def finalize_options(self):
|
||||
orig.build_py.finalize_options(self)
|
||||
@@ -33,9 +41,18 @@ class build_py(orig.build_py):
|
||||
del self.__dict__['data_files']
|
||||
self.__updated_files = []
|
||||
|
||||
def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1,
|
||||
link=None, level=1):
|
||||
# Overwrite base class to allow using links
|
||||
if link:
|
||||
infile = str(Path(infile).resolve())
|
||||
outfile = str(Path(outfile).resolve())
|
||||
return super().copy_file(infile, outfile, preserve_mode, preserve_times,
|
||||
link, level)
|
||||
|
||||
def run(self):
|
||||
"""Build modules, packages, and copy data files to build directory"""
|
||||
if not self.py_modules and not self.packages:
|
||||
if not (self.py_modules or self.packages) or self.editable_mode:
|
||||
return
|
||||
|
||||
if self.py_modules:
|
||||
@@ -67,6 +84,16 @@ class build_py(orig.build_py):
|
||||
self.analyze_manifest()
|
||||
return list(map(self._get_pkg_data_files, self.packages or ()))
|
||||
|
||||
def get_data_files_without_manifest(self):
|
||||
"""
|
||||
Generate list of ``(package,src_dir,build_dir,filenames)`` tuples,
|
||||
but without triggering any attempt to analyze or build the manifest.
|
||||
"""
|
||||
# Prevent eventual errors from unset `manifest_files`
|
||||
# (that would otherwise be set by `analyze_manifest`)
|
||||
self.__dict__.setdefault('manifest_files', {})
|
||||
return list(map(self._get_pkg_data_files, self.packages or ()))
|
||||
|
||||
def _get_pkg_data_files(self, package):
|
||||
# Locate package source directory
|
||||
src_dir = self.get_package_dir(package)
|
||||
@@ -88,7 +115,7 @@ class build_py(orig.build_py):
|
||||
package,
|
||||
src_dir,
|
||||
)
|
||||
globs_expanded = map(glob, patterns)
|
||||
globs_expanded = map(partial(glob, recursive=True), patterns)
|
||||
# flatten the expanded globs into an iterable of matches
|
||||
globs_matches = itertools.chain.from_iterable(globs_expanded)
|
||||
glob_files = filter(os.path.isfile, globs_matches)
|
||||
@@ -98,16 +125,41 @@ class build_py(orig.build_py):
|
||||
)
|
||||
return self.exclude_data_files(package, src_dir, files)
|
||||
|
||||
def build_package_data(self):
|
||||
"""Copy data files into build directory"""
|
||||
def get_outputs(self, include_bytecode=1) -> List[str]:
|
||||
"""See :class:`setuptools.commands.build.SubCommand`"""
|
||||
if self.editable_mode:
|
||||
return list(self.get_output_mapping().keys())
|
||||
return super().get_outputs(include_bytecode)
|
||||
|
||||
def get_output_mapping(self) -> Dict[str, str]:
|
||||
"""See :class:`setuptools.commands.build.SubCommand`"""
|
||||
mapping = itertools.chain(
|
||||
self._get_package_data_output_mapping(),
|
||||
self._get_module_mapping(),
|
||||
)
|
||||
return dict(sorted(mapping, key=lambda x: x[0]))
|
||||
|
||||
def _get_module_mapping(self) -> Iterator[Tuple[str, str]]:
|
||||
"""Iterate over all modules producing (dest, src) pairs."""
|
||||
for (package, module, module_file) in self.find_all_modules():
|
||||
package = package.split('.')
|
||||
filename = self.get_module_outfile(self.build_lib, package, module)
|
||||
yield (filename, module_file)
|
||||
|
||||
def _get_package_data_output_mapping(self) -> Iterator[Tuple[str, str]]:
|
||||
"""Iterate over package data producing (dest, src) pairs."""
|
||||
for package, src_dir, build_dir, filenames in self.data_files:
|
||||
for filename in filenames:
|
||||
target = os.path.join(build_dir, filename)
|
||||
self.mkpath(os.path.dirname(target))
|
||||
srcfile = os.path.join(src_dir, filename)
|
||||
outf, copied = self.copy_file(srcfile, target)
|
||||
make_writable(target)
|
||||
srcfile = os.path.abspath(srcfile)
|
||||
yield (target, srcfile)
|
||||
|
||||
def build_package_data(self):
|
||||
"""Copy data files into build directory"""
|
||||
for target, srcfile in self._get_package_data_output_mapping():
|
||||
self.mkpath(os.path.dirname(target))
|
||||
_outf, _copied = self.copy_file(srcfile, target)
|
||||
make_writable(target)
|
||||
|
||||
def analyze_manifest(self):
|
||||
self.manifest_files = mf = {}
|
||||
@@ -118,9 +170,21 @@ class build_py(orig.build_py):
|
||||
# Locate package source directory
|
||||
src_dirs[assert_relative(self.get_package_dir(package))] = package
|
||||
|
||||
self.run_command('egg_info')
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
for path in ei_cmd.filelist.files:
|
||||
if (
|
||||
getattr(self, 'existing_egg_info_dir', None)
|
||||
and Path(self.existing_egg_info_dir, "SOURCES.txt").exists()
|
||||
):
|
||||
egg_info_dir = self.existing_egg_info_dir
|
||||
manifest = Path(egg_info_dir, "SOURCES.txt")
|
||||
files = manifest.read_text(encoding="utf-8").splitlines()
|
||||
else:
|
||||
self.run_command('egg_info')
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
egg_info_dir = ei_cmd.egg_info
|
||||
files = ei_cmd.filelist.files
|
||||
|
||||
check = _IncludePackageDataAbuse()
|
||||
for path in self._filter_build_files(files, egg_info_dir):
|
||||
d, f = os.path.split(assert_relative(path))
|
||||
prev = None
|
||||
oldf = f
|
||||
@@ -129,10 +193,34 @@ class build_py(orig.build_py):
|
||||
d, df = os.path.split(d)
|
||||
f = os.path.join(df, f)
|
||||
if d in src_dirs:
|
||||
if path.endswith('.py') and f == oldf:
|
||||
continue # it's a module, not data
|
||||
if f == oldf:
|
||||
if check.is_module(f):
|
||||
continue # it's a module, not data
|
||||
else:
|
||||
importable = check.importable_subpackage(src_dirs[d], f)
|
||||
if importable:
|
||||
check.warn(importable)
|
||||
mf.setdefault(src_dirs[d], []).append(path)
|
||||
|
||||
def _filter_build_files(self, files: Iterable[str], egg_info: str) -> Iterator[str]:
|
||||
"""
|
||||
``build_meta`` may try to create egg_info outside of the project directory,
|
||||
and this can be problematic for certain plugins (reported in issue #3500).
|
||||
|
||||
Extensions might also include between their sources files created on the
|
||||
``build_lib`` and ``build_temp`` directories.
|
||||
|
||||
This function should filter this case of invalid files out.
|
||||
"""
|
||||
build = self.get_finalized_command("build")
|
||||
build_dirs = (egg_info, self.build_lib, build.build_temp, build.build_base)
|
||||
norm_dirs = [os.path.normpath(p) for p in build_dirs if p]
|
||||
|
||||
for file in files:
|
||||
norm_path = os.path.normpath(file)
|
||||
if not os.path.isabs(file) or all(d not in norm_path for d in norm_dirs):
|
||||
yield file
|
||||
|
||||
def get_data_files(self):
|
||||
pass # Lazily compute data files in _get_data_files() function.
|
||||
|
||||
@@ -169,6 +257,8 @@ class build_py(orig.build_py):
|
||||
def initialize_options(self):
|
||||
self.packages_checked = {}
|
||||
orig.build_py.initialize_options(self)
|
||||
self.editable_mode = False
|
||||
self.existing_egg_info_dir = None
|
||||
|
||||
def get_package_dir(self, package):
|
||||
res = orig.build_py.get_package_dir(self, package)
|
||||
@@ -230,3 +320,49 @@ def assert_relative(path):
|
||||
% path
|
||||
)
|
||||
raise DistutilsSetupError(msg)
|
||||
|
||||
|
||||
class _IncludePackageDataAbuse:
|
||||
"""Inform users that package or module is included as 'data file'"""
|
||||
|
||||
MESSAGE = """\
|
||||
Installing {importable!r} as data is deprecated, please list it in `packages`.
|
||||
!!\n\n
|
||||
############################
|
||||
# Package would be ignored #
|
||||
############################
|
||||
Python recognizes {importable!r} as an importable package,
|
||||
but it is not listed in the `packages` configuration of setuptools.
|
||||
|
||||
{importable!r} has been automatically added to the distribution only
|
||||
because it may contain data files, but this behavior is likely to change
|
||||
in future versions of setuptools (and therefore is considered deprecated).
|
||||
|
||||
Please make sure that {importable!r} is included as a package by using
|
||||
the `packages` configuration field or the proper discovery methods
|
||||
(for example by using `find_namespace_packages(...)`/`find_namespace:`
|
||||
instead of `find_packages(...)`/`find:`).
|
||||
|
||||
You can read more about "package discovery" and "data files" on setuptools
|
||||
documentation page.
|
||||
\n\n!!
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._already_warned = set()
|
||||
|
||||
def is_module(self, file):
|
||||
return file.endswith(".py") and file[:-len(".py")].isidentifier()
|
||||
|
||||
def importable_subpackage(self, parent, file):
|
||||
pkg = Path(file).parent
|
||||
parts = list(itertools.takewhile(str.isidentifier, pkg.parts))
|
||||
if parts:
|
||||
return ".".join([parent, *parts])
|
||||
return None
|
||||
|
||||
def warn(self, importable):
|
||||
if importable not in self._already_warned:
|
||||
msg = textwrap.dedent(self.MESSAGE).format(importable=importable)
|
||||
warnings.warn(msg, SetuptoolsDeprecationWarning, stacklevel=2)
|
||||
self._already_warned.add(importable)
|
||||
|
@@ -4,9 +4,18 @@ As defined in the wheel specification
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import warnings
|
||||
from contextlib import contextmanager
|
||||
from inspect import cleandoc
|
||||
from pathlib import Path
|
||||
|
||||
from distutils.core import Command
|
||||
from distutils import log
|
||||
from setuptools.extern import packaging
|
||||
from setuptools._deprecation_warning import SetuptoolsDeprecationWarning
|
||||
|
||||
|
||||
class dist_info(Command):
|
||||
@@ -15,22 +24,119 @@ class dist_info(Command):
|
||||
|
||||
user_options = [
|
||||
('egg-base=', 'e', "directory containing .egg-info directories"
|
||||
" (default: top of the source tree)"),
|
||||
" (default: top of the source tree)"
|
||||
" DEPRECATED: use --output-dir."),
|
||||
('output-dir=', 'o', "directory inside of which the .dist-info will be"
|
||||
"created (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]"),
|
||||
('keep-egg-info', None, "*TRANSITIONAL* will be removed in the future"),
|
||||
]
|
||||
|
||||
boolean_options = ['tag-date', 'keep-egg-info']
|
||||
negative_opt = {'no-date': 'tag-date'}
|
||||
|
||||
def initialize_options(self):
|
||||
self.egg_base = None
|
||||
self.output_dir = None
|
||||
self.name = None
|
||||
self.dist_info_dir = None
|
||||
self.tag_date = None
|
||||
self.tag_build = None
|
||||
self.keep_egg_info = False
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
if self.egg_base:
|
||||
msg = "--egg-base is deprecated for dist_info command. Use --output-dir."
|
||||
warnings.warn(msg, SetuptoolsDeprecationWarning)
|
||||
self.output_dir = self.egg_base or self.output_dir
|
||||
|
||||
dist = self.distribution
|
||||
project_dir = dist.src_root or os.curdir
|
||||
self.output_dir = Path(self.output_dir or project_dir)
|
||||
|
||||
egg_info = self.reinitialize_command("egg_info")
|
||||
egg_info.egg_base = str(self.output_dir)
|
||||
|
||||
if self.tag_date:
|
||||
egg_info.tag_date = self.tag_date
|
||||
else:
|
||||
self.tag_date = egg_info.tag_date
|
||||
|
||||
if self.tag_build:
|
||||
egg_info.tag_build = self.tag_build
|
||||
else:
|
||||
self.tag_build = egg_info.tag_build
|
||||
|
||||
egg_info.finalize_options()
|
||||
self.egg_info = egg_info
|
||||
|
||||
name = _safe(dist.get_name())
|
||||
version = _version(dist.get_version())
|
||||
self.name = f"{name}-{version}"
|
||||
self.dist_info_dir = os.path.join(self.output_dir, f"{self.name}.dist-info")
|
||||
|
||||
@contextmanager
|
||||
def _maybe_bkp_dir(self, dir_path: str, requires_bkp: bool):
|
||||
if requires_bkp:
|
||||
bkp_name = f"{dir_path}.__bkp__"
|
||||
_rm(bkp_name, ignore_errors=True)
|
||||
_copy(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_rm(dir_path, ignore_errors=True)
|
||||
shutil.move(bkp_name, dir_path)
|
||||
else:
|
||||
yield
|
||||
|
||||
def run(self):
|
||||
egg_info = self.get_finalized_command('egg_info')
|
||||
egg_info.egg_base = self.egg_base
|
||||
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)))
|
||||
self.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.egg_info.run()
|
||||
egg_info_dir = self.egg_info.egg_info
|
||||
assert os.path.isdir(egg_info_dir), ".egg-info dir should have been created"
|
||||
|
||||
log.info("creating '{}'".format(os.path.abspath(self.dist_info_dir)))
|
||||
bdist_wheel = self.get_finalized_command('bdist_wheel')
|
||||
bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir)
|
||||
|
||||
# TODO: if bdist_wheel if merged into setuptools, just add "keep_egg_info" there
|
||||
with self._maybe_bkp_dir(egg_info_dir, self.keep_egg_info):
|
||||
bdist_wheel.egg2dist(egg_info_dir, self.dist_info_dir)
|
||||
|
||||
|
||||
def _safe(component: str) -> str:
|
||||
"""Escape a component used to form a wheel name according to PEP 491"""
|
||||
return re.sub(r"[^\w\d.]+", "_", component)
|
||||
|
||||
|
||||
def _version(version: str) -> str:
|
||||
"""Convert an arbitrary string to a version string."""
|
||||
v = version.replace(' ', '.')
|
||||
try:
|
||||
return str(packaging.version.Version(v)).replace("-", "_")
|
||||
except packaging.version.InvalidVersion:
|
||||
msg = f"""Invalid version: {version!r}.
|
||||
!!\n\n
|
||||
###################
|
||||
# Invalid version #
|
||||
###################
|
||||
{version!r} is not valid according to PEP 440.\n
|
||||
Please make sure specify a valid version for your package.
|
||||
Also note that future releases of setuptools may halt the build process
|
||||
if an invalid version is given.
|
||||
\n\n!!
|
||||
"""
|
||||
warnings.warn(cleandoc(msg))
|
||||
return _safe(v).strip("_")
|
||||
|
||||
|
||||
def _rm(dir_name, **opts):
|
||||
if os.path.isdir(dir_name):
|
||||
shutil.rmtree(dir_name, **opts)
|
||||
|
||||
|
||||
def _copy(src, dst, **opts):
|
||||
if sys.version_info < (3, 8):
|
||||
opts.pop("dirs_exist_ok", None)
|
||||
shutil.copytree(src, dst, **opts)
|
||||
|
@@ -6,7 +6,7 @@ A tool for doing automatic download/extract/build of distutils-based Python
|
||||
packages. For detailed documentation, see the accompanying EasyInstall.txt
|
||||
file, or visit the `EasyInstall home page`__.
|
||||
|
||||
__ https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html
|
||||
__ https://setuptools.pypa.io/en/latest/deprecated/easy_install.html
|
||||
|
||||
"""
|
||||
|
||||
@@ -17,10 +17,10 @@ from distutils.errors import (
|
||||
DistutilsArgError, DistutilsOptionError,
|
||||
DistutilsError, DistutilsPlatformError,
|
||||
)
|
||||
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
|
||||
from distutils import log, dir_util
|
||||
from distutils.command.build_scripts import first_line_re
|
||||
from distutils.spawn import find_executable
|
||||
from distutils.command import install
|
||||
import sys
|
||||
import os
|
||||
import zipimport
|
||||
@@ -39,9 +39,10 @@ import subprocess
|
||||
import shlex
|
||||
import io
|
||||
import configparser
|
||||
import sysconfig
|
||||
|
||||
|
||||
from sysconfig import get_config_vars, get_path
|
||||
from sysconfig import get_path
|
||||
|
||||
from setuptools import SetuptoolsDeprecationWarning
|
||||
|
||||
@@ -55,18 +56,21 @@ from setuptools.package_index import (
|
||||
from setuptools.command import bdist_egg, egg_info
|
||||
from setuptools.wheel import Wheel
|
||||
from pkg_resources import (
|
||||
yield_lines, normalize_path, resource_string, ensure_directory,
|
||||
normalize_path, resource_string,
|
||||
get_distribution, find_distributions, Environment, Requirement,
|
||||
Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
|
||||
VersionConflict, DEVELOP_DIST,
|
||||
)
|
||||
import pkg_resources
|
||||
from .._path import ensure_directory
|
||||
from ..extern.jaraco.text import yield_lines
|
||||
|
||||
|
||||
# Turn on PEP440Warnings
|
||||
warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
|
||||
|
||||
__all__ = [
|
||||
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
|
||||
'easy_install', 'PthDistributions', 'extract_wininst_cfg',
|
||||
'get_exe_prefixes',
|
||||
]
|
||||
|
||||
@@ -75,22 +79,6 @@ def is_64bit():
|
||||
return struct.calcsize("P") == 8
|
||||
|
||||
|
||||
def samefile(p1, p2):
|
||||
"""
|
||||
Determine if two paths reference the same file.
|
||||
|
||||
Augments os.path.samefile to work on Windows and
|
||||
suppresses errors if the path doesn't exist.
|
||||
"""
|
||||
both_exist = os.path.exists(p1) and os.path.exists(p2)
|
||||
use_samefile = hasattr(os.path, 'samefile') and both_exist
|
||||
if use_samefile:
|
||||
return os.path.samefile(p1, p2)
|
||||
norm_p1 = os.path.normpath(os.path.normcase(p1))
|
||||
norm_p2 = os.path.normpath(os.path.normcase(p2))
|
||||
return norm_p1 == norm_p2
|
||||
|
||||
|
||||
def _to_bytes(s):
|
||||
return s.encode('utf8')
|
||||
|
||||
@@ -153,6 +141,12 @@ class easy_install(Command):
|
||||
create_index = PackageIndex
|
||||
|
||||
def initialize_options(self):
|
||||
warnings.warn(
|
||||
"easy_install command is deprecated. "
|
||||
"Use build and pip and other standards-based tools.",
|
||||
EasyInstallDeprecationWarning,
|
||||
)
|
||||
|
||||
# the --user option seems to be an opt-in one,
|
||||
# so the default should be False.
|
||||
self.user = 0
|
||||
@@ -175,12 +169,8 @@ class easy_install(Command):
|
||||
self.install_data = None
|
||||
self.install_base = None
|
||||
self.install_platbase = None
|
||||
if site.ENABLE_USER_SITE:
|
||||
self.install_userbase = site.USER_BASE
|
||||
self.install_usersite = site.USER_SITE
|
||||
else:
|
||||
self.install_userbase = None
|
||||
self.install_usersite = None
|
||||
self.install_userbase = site.USER_BASE
|
||||
self.install_usersite = site.USER_SITE
|
||||
self.no_find_links = None
|
||||
|
||||
# Options not specifiable via command line
|
||||
@@ -230,28 +220,38 @@ class easy_install(Command):
|
||||
self.version and self._render_version()
|
||||
|
||||
py_version = sys.version.split()[0]
|
||||
prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix')
|
||||
|
||||
self.config_vars = {
|
||||
self.config_vars = dict(sysconfig.get_config_vars())
|
||||
|
||||
self.config_vars.update({
|
||||
'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': py_version[0:3],
|
||||
'py_version_nodot': py_version[0] + py_version[2],
|
||||
'sys_prefix': prefix,
|
||||
'prefix': prefix,
|
||||
'sys_exec_prefix': exec_prefix,
|
||||
'exec_prefix': exec_prefix,
|
||||
'py_version_short': f'{sys.version_info.major}.{sys.version_info.minor}',
|
||||
'py_version_nodot': f'{sys.version_info.major}{sys.version_info.minor}',
|
||||
'sys_prefix': self.config_vars['prefix'],
|
||||
'sys_exec_prefix': self.config_vars['exec_prefix'],
|
||||
# Only python 3.2+ has abiflags
|
||||
'abiflags': getattr(sys, 'abiflags', ''),
|
||||
}
|
||||
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
|
||||
})
|
||||
with contextlib.suppress(AttributeError):
|
||||
# only for distutils outside stdlib
|
||||
self.config_vars.update({
|
||||
'implementation_lower': install._get_implementation().lower(),
|
||||
'implementation': install._get_implementation(),
|
||||
})
|
||||
|
||||
if site.ENABLE_USER_SITE:
|
||||
self.config_vars['userbase'] = self.install_userbase
|
||||
self.config_vars['usersite'] = self.install_usersite
|
||||
# pypa/distutils#113 Python 3.9 compat
|
||||
self.config_vars.setdefault(
|
||||
'py_version_nodot_plat',
|
||||
getattr(sys, 'windir', '').replace('.', ''),
|
||||
)
|
||||
|
||||
elif self.user:
|
||||
self.config_vars['userbase'] = self.install_userbase
|
||||
self.config_vars['usersite'] = self.install_usersite
|
||||
if self.user and not site.ENABLE_USER_SITE:
|
||||
log.warn("WARNING: The user site-packages directory is disabled.")
|
||||
|
||||
self._fix_install_dir_for_user_site()
|
||||
@@ -287,27 +287,14 @@ class easy_install(Command):
|
||||
self.script_dir = self.install_scripts
|
||||
# default --record from the install command
|
||||
self.set_undefined_options('install', ('record', 'record'))
|
||||
# Should this be moved to the if statement below? It's not used
|
||||
# elsewhere
|
||||
normpath = map(normalize_path, sys.path)
|
||||
self.all_site_dirs = get_site_dirs()
|
||||
if self.site_dirs is not None:
|
||||
site_dirs = [
|
||||
os.path.expanduser(s.strip()) for s in
|
||||
self.site_dirs.split(',')
|
||||
]
|
||||
for d in site_dirs:
|
||||
if not os.path.isdir(d):
|
||||
log.warn("%s (in --site-dirs) does not exist", d)
|
||||
elif normalize_path(d) not in normpath:
|
||||
raise DistutilsOptionError(
|
||||
d + " (in --site-dirs) is not on sys.path"
|
||||
)
|
||||
else:
|
||||
self.all_site_dirs.append(normalize_path(d))
|
||||
self.all_site_dirs.extend(self._process_site_dirs(self.site_dirs))
|
||||
|
||||
if not self.editable:
|
||||
self.check_site_dir()
|
||||
self.index_url = self.index_url or "https://pypi.org/simple/"
|
||||
default_index = os.getenv("__EASYINSTALL_INDEX", "https://pypi.org/simple/")
|
||||
# ^ Private API for testing purposes only
|
||||
self.index_url = self.index_url or default_index
|
||||
self.shadow_path = self.all_site_dirs[:]
|
||||
for path_item in self.install_dir, normalize_path(self.script_dir):
|
||||
if path_item not in self.shadow_path:
|
||||
@@ -333,15 +320,7 @@ class easy_install(Command):
|
||||
if not self.no_find_links:
|
||||
self.package_index.add_find_links(self.find_links)
|
||||
self.set_undefined_options('install_lib', ('optimize', 'optimize'))
|
||||
if not isinstance(self.optimize, int):
|
||||
try:
|
||||
self.optimize = int(self.optimize)
|
||||
if not (0 <= self.optimize <= 2):
|
||||
raise ValueError
|
||||
except ValueError as e:
|
||||
raise DistutilsOptionError(
|
||||
"--optimize must be 0, 1, or 2"
|
||||
) from e
|
||||
self.optimize = self._validate_optimize(self.optimize)
|
||||
|
||||
if self.editable and not self.build_directory:
|
||||
raise DistutilsArgError(
|
||||
@@ -353,11 +332,44 @@ class easy_install(Command):
|
||||
|
||||
self.outputs = []
|
||||
|
||||
@staticmethod
|
||||
def _process_site_dirs(site_dirs):
|
||||
if site_dirs is None:
|
||||
return
|
||||
|
||||
normpath = map(normalize_path, sys.path)
|
||||
site_dirs = [
|
||||
os.path.expanduser(s.strip()) for s in
|
||||
site_dirs.split(',')
|
||||
]
|
||||
for d in site_dirs:
|
||||
if not os.path.isdir(d):
|
||||
log.warn("%s (in --site-dirs) does not exist", d)
|
||||
elif normalize_path(d) not in normpath:
|
||||
raise DistutilsOptionError(
|
||||
d + " (in --site-dirs) is not on sys.path"
|
||||
)
|
||||
else:
|
||||
yield normalize_path(d)
|
||||
|
||||
@staticmethod
|
||||
def _validate_optimize(value):
|
||||
try:
|
||||
value = int(value)
|
||||
if value not in range(3):
|
||||
raise ValueError
|
||||
except ValueError as e:
|
||||
raise DistutilsOptionError(
|
||||
"--optimize must be 0, 1, or 2"
|
||||
) from e
|
||||
|
||||
return value
|
||||
|
||||
def _fix_install_dir_for_user_site(self):
|
||||
"""
|
||||
Fix the install_dir if "--user" was used.
|
||||
"""
|
||||
if not self.user or not site.ENABLE_USER_SITE:
|
||||
if not self.user:
|
||||
return
|
||||
|
||||
self.create_home_path()
|
||||
@@ -365,7 +377,7 @@ class easy_install(Command):
|
||||
msg = "User base directory is not specified"
|
||||
raise DistutilsPlatformError(msg)
|
||||
self.install_base = self.install_platbase = self.install_userbase
|
||||
scheme_name = os.name.replace('posix', 'unix') + '_user'
|
||||
scheme_name = f'{os.name}_user'
|
||||
self.select_scheme(scheme_name)
|
||||
|
||||
def _expand_attrs(self, attrs):
|
||||
@@ -513,7 +525,7 @@ class easy_install(Command):
|
||||
For information on other options, you may wish to consult the
|
||||
documentation at:
|
||||
|
||||
https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html
|
||||
https://setuptools.pypa.io/en/latest/deprecated/easy_install.html
|
||||
|
||||
Please make the appropriate changes for your system and try again.
|
||||
""").lstrip() # noqa
|
||||
@@ -705,13 +717,11 @@ class easy_install(Command):
|
||||
return dist
|
||||
|
||||
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!
|
||||
scheme = INSTALL_SCHEMES[name]
|
||||
for key in SCHEME_KEYS:
|
||||
attrname = 'install_' + key
|
||||
if getattr(self, attrname) is None:
|
||||
setattr(self, attrname, scheme[key])
|
||||
try:
|
||||
install._select_scheme(self, name)
|
||||
except AttributeError:
|
||||
# stdlib distutils
|
||||
install.install.select_scheme(self, name.replace('posix', 'unix'))
|
||||
|
||||
# FIXME: 'easy_install.process_distribution' is too complex (12)
|
||||
def process_distribution( # noqa: C901
|
||||
@@ -908,7 +918,9 @@ class easy_install(Command):
|
||||
ensure_directory(destination)
|
||||
|
||||
dist = self.egg_distribution(egg_path)
|
||||
if not samefile(egg_path, destination):
|
||||
if not (
|
||||
os.path.exists(destination) and os.path.samefile(egg_path, destination)
|
||||
):
|
||||
if os.path.isdir(destination) and not os.path.islink(destination):
|
||||
dir_util.remove_tree(destination, dry_run=self.dry_run)
|
||||
elif os.path.exists(destination):
|
||||
@@ -1306,7 +1318,7 @@ class easy_install(Command):
|
||||
* You can set up the installation directory to support ".pth" files by
|
||||
using one of the approaches described here:
|
||||
|
||||
https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html#custom-installation-locations
|
||||
https://setuptools.pypa.io/en/latest/deprecated/easy_install.html#custom-installation-locations
|
||||
|
||||
|
||||
Please make the appropriate changes for your system and try again.
|
||||
@@ -1317,7 +1329,7 @@ class easy_install(Command):
|
||||
if not self.user:
|
||||
return
|
||||
home = convert_path(os.path.expanduser("~"))
|
||||
for name, path in self.config_vars.items():
|
||||
for path in only_strs(self.config_vars.values()):
|
||||
if path.startswith(home) and not os.path.isdir(path):
|
||||
self.debug_print("os.makedirs('%s', 0o700)" % path)
|
||||
os.makedirs(path, 0o700)
|
||||
@@ -1339,7 +1351,7 @@ class easy_install(Command):
|
||||
|
||||
if self.prefix:
|
||||
# Set default install_dir/scripts from --prefix
|
||||
config_vars = config_vars.copy()
|
||||
config_vars = dict(config_vars)
|
||||
config_vars['base'] = self.prefix
|
||||
scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME)
|
||||
for attr, val in scheme.items():
|
||||
@@ -1566,7 +1578,7 @@ class PthDistributions(Environment):
|
||||
self.sitedirs = list(map(normalize_path, sitedirs))
|
||||
self.basedir = normalize_path(os.path.dirname(self.filename))
|
||||
self._load()
|
||||
Environment.__init__(self, [], None, None)
|
||||
super().__init__([], None, None)
|
||||
for path in yield_lines(self.paths):
|
||||
list(map(self.add, find_distributions(path, True)))
|
||||
|
||||
@@ -1639,14 +1651,14 @@ class PthDistributions(Environment):
|
||||
if new_path:
|
||||
self.paths.append(dist.location)
|
||||
self.dirty = True
|
||||
Environment.add(self, dist)
|
||||
super().add(dist)
|
||||
|
||||
def remove(self, dist):
|
||||
"""Remove `dist` from the distribution map"""
|
||||
while dist.location in self.paths:
|
||||
self.paths.remove(dist.location)
|
||||
self.dirty = True
|
||||
Environment.remove(self, dist)
|
||||
super().remove(dist)
|
||||
|
||||
def make_relative(self, path):
|
||||
npath, last = os.path.split(normalize_path(path))
|
||||
@@ -2263,7 +2275,10 @@ def get_win_launcher(type):
|
||||
"""
|
||||
launcher_fn = '%s.exe' % type
|
||||
if is_64bit():
|
||||
launcher_fn = launcher_fn.replace(".", "-64.")
|
||||
if get_platform() == "win-arm64":
|
||||
launcher_fn = launcher_fn.replace(".", "-arm64.")
|
||||
else:
|
||||
launcher_fn = launcher_fn.replace(".", "-64.")
|
||||
else:
|
||||
launcher_fn = launcher_fn.replace(".", "-32.")
|
||||
return resource_string('setuptools', launcher_fn)
|
||||
@@ -2284,6 +2299,13 @@ def current_umask():
|
||||
return tmp
|
||||
|
||||
|
||||
def only_strs(values):
|
||||
"""
|
||||
Exclude non-str values. Ref #3063.
|
||||
"""
|
||||
return filter(lambda val: isinstance(val, str), values)
|
||||
|
||||
|
||||
class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
|
||||
"""
|
||||
Warning for EasyInstall deprecations, bypassing suppression.
|
||||
|
@@ -17,18 +17,22 @@ import warnings
|
||||
import time
|
||||
import collections
|
||||
|
||||
from .._importlib import metadata
|
||||
from .. import _entry_points
|
||||
|
||||
from setuptools import Command
|
||||
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)
|
||||
Requirement, safe_name, parse_version,
|
||||
safe_version, to_filename)
|
||||
import setuptools.unicode_utils as unicode_utils
|
||||
from setuptools.glob import glob
|
||||
|
||||
from setuptools.extern import packaging
|
||||
from setuptools.extern.jaraco.text import yield_lines
|
||||
from setuptools import SetuptoolsDeprecationWarning
|
||||
|
||||
|
||||
@@ -132,11 +136,21 @@ class InfoCommon:
|
||||
in which case the version string already contains all tags.
|
||||
"""
|
||||
return (
|
||||
version if self.vtags and version.endswith(self.vtags)
|
||||
version if self.vtags and self._already_tagged(version)
|
||||
else version + self.vtags
|
||||
)
|
||||
|
||||
def tags(self):
|
||||
def _already_tagged(self, version: str) -> bool:
|
||||
# Depending on their format, tags may change with version normalization.
|
||||
# So in addition the regular tags, we have to search for the normalized ones.
|
||||
return version.endswith(self.vtags) or version.endswith(self._safe_tags())
|
||||
|
||||
def _safe_tags(self) -> str:
|
||||
# To implement this we can rely on `safe_version` pretending to be version 0
|
||||
# followed by tags. Then we simply discard the starting 0 (fake version number)
|
||||
return safe_version(f"0{self.vtags}")[1:]
|
||||
|
||||
def tags(self) -> str:
|
||||
version = ''
|
||||
if self.tag_build:
|
||||
version += self.tag_build
|
||||
@@ -168,6 +182,7 @@ class egg_info(InfoCommon, Command):
|
||||
self.egg_info = None
|
||||
self.egg_version = None
|
||||
self.broken_egg_info = False
|
||||
self.ignore_egg_info_in_manifest = False
|
||||
|
||||
####################################
|
||||
# allow the 'tag_svn_revision' to be detected and
|
||||
@@ -205,12 +220,8 @@ class egg_info(InfoCommon, Command):
|
||||
|
||||
try:
|
||||
is_version = isinstance(parsed_version, packaging.version.Version)
|
||||
spec = (
|
||||
"%s==%s" if is_version else "%s===%s"
|
||||
)
|
||||
list(
|
||||
parse_requirements(spec % (self.egg_name, self.egg_version))
|
||||
)
|
||||
spec = "%s==%s" if is_version else "%s===%s"
|
||||
Requirement(spec % (self.egg_name, self.egg_version))
|
||||
except ValueError as e:
|
||||
raise distutils.errors.DistutilsOptionError(
|
||||
"Invalid distribution name or version syntax: %s-%s" %
|
||||
@@ -285,10 +296,8 @@ class egg_info(InfoCommon, Command):
|
||||
def run(self):
|
||||
self.mkpath(self.egg_info)
|
||||
os.utime(self.egg_info, None)
|
||||
installer = self.distribution.fetch_build_egg
|
||||
for ep in iter_entry_points('egg_info.writers'):
|
||||
ep.require(installer=installer)
|
||||
writer = ep.resolve()
|
||||
for ep in metadata.entry_points(group='egg_info.writers'):
|
||||
writer = ep.load()
|
||||
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
|
||||
@@ -302,6 +311,7 @@ class egg_info(InfoCommon, Command):
|
||||
"""Generate SOURCES.txt manifest file"""
|
||||
manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
|
||||
mm = manifest_maker(self.distribution)
|
||||
mm.ignore_egg_info_dir = self.ignore_egg_info_in_manifest
|
||||
mm.manifest = manifest_filename
|
||||
mm.run()
|
||||
self.filelist = mm.filelist
|
||||
@@ -325,6 +335,10 @@ class egg_info(InfoCommon, Command):
|
||||
class FileList(_FileList):
|
||||
# Implementations of the various MANIFEST.in commands
|
||||
|
||||
def __init__(self, warn=None, debug_print=None, ignore_egg_info_dir=False):
|
||||
super().__init__(warn, debug_print)
|
||||
self.ignore_egg_info_dir = ignore_egg_info_dir
|
||||
|
||||
def process_template_line(self, line):
|
||||
# Parse the line: split it up, make sure the right number of words
|
||||
# is there, and return the relevant words. 'action' is always
|
||||
@@ -514,6 +528,10 @@ class FileList(_FileList):
|
||||
return False
|
||||
|
||||
try:
|
||||
# ignore egg-info paths
|
||||
is_egg_info = ".egg-info" in u_path or b".egg-info" in utf8_path
|
||||
if self.ignore_egg_info_dir and is_egg_info:
|
||||
return False
|
||||
# accept is either way checks out
|
||||
if os.path.exists(u_path) or os.path.exists(utf8_path):
|
||||
return True
|
||||
@@ -530,12 +548,13 @@ class manifest_maker(sdist):
|
||||
self.prune = 1
|
||||
self.manifest_only = 1
|
||||
self.force_manifest = 1
|
||||
self.ignore_egg_info_dir = False
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
self.filelist = FileList()
|
||||
self.filelist = FileList(ignore_egg_info_dir=self.ignore_egg_info_dir)
|
||||
if not os.path.exists(self.manifest):
|
||||
self.write_manifest() # it must exist so it'll get in the list
|
||||
self.add_defaults()
|
||||
@@ -608,6 +627,27 @@ class manifest_maker(sdist):
|
||||
self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
|
||||
is_regex=1)
|
||||
|
||||
def _safe_data_files(self, build_py):
|
||||
"""
|
||||
The parent class implementation of this method
|
||||
(``sdist``) will try to include data files, which
|
||||
might cause recursion problems when
|
||||
``include_package_data=True``.
|
||||
|
||||
Therefore, avoid triggering any attempt of
|
||||
analyzing/building the manifest again.
|
||||
"""
|
||||
if hasattr(build_py, 'get_data_files_without_manifest'):
|
||||
return build_py.get_data_files_without_manifest()
|
||||
|
||||
warnings.warn(
|
||||
"Custom 'build_py' does not implement "
|
||||
"'get_data_files_without_manifest'.\nPlease extend command classes"
|
||||
" from setuptools instead of distutils.",
|
||||
SetuptoolsDeprecationWarning
|
||||
)
|
||||
return build_py.get_data_files()
|
||||
|
||||
|
||||
def write_file(filename, contents):
|
||||
"""Create a file with the specified name and write 'contents' (a
|
||||
@@ -698,20 +738,9 @@ def write_arg(cmd, basename, filename, force=False):
|
||||
|
||||
|
||||
def write_entries(cmd, basename, filename):
|
||||
ep = cmd.distribution.entry_points
|
||||
|
||||
if isinstance(ep, str) or ep is None:
|
||||
data = ep
|
||||
elif ep is not None:
|
||||
data = []
|
||||
for section, contents in sorted(ep.items()):
|
||||
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 = ''.join(data)
|
||||
|
||||
cmd.write_or_delete_file('entry points', filename, data, True)
|
||||
eps = _entry_points.load(cmd.distribution.entry_points)
|
||||
defn = _entry_points.render(eps)
|
||||
cmd.write_or_delete_file('entry points', filename, defn, True)
|
||||
|
||||
|
||||
def get_pkg_info_revision():
|
||||
|
@@ -30,6 +30,13 @@ class install(orig.install):
|
||||
_nc = dict(new_commands)
|
||||
|
||||
def initialize_options(self):
|
||||
|
||||
warnings.warn(
|
||||
"setup.py install is deprecated. "
|
||||
"Use build and pip and other standards-based tools.",
|
||||
setuptools.SetuptoolsDeprecationWarning,
|
||||
)
|
||||
|
||||
orig.install.initialize_options(self)
|
||||
self.old_and_unmanageable = None
|
||||
self.single_version_externally_managed = None
|
||||
@@ -84,14 +91,21 @@ class install(orig.install):
|
||||
msg = "For best results, pass -X:Frames to enable call stack."
|
||||
warnings.warn(msg)
|
||||
return True
|
||||
res = inspect.getouterframes(run_frame)[2]
|
||||
caller, = res[:1]
|
||||
info = inspect.getframeinfo(caller)
|
||||
caller_module = caller.f_globals.get('__name__', '')
|
||||
return (
|
||||
caller_module == 'distutils.dist'
|
||||
and info.function == 'run_commands'
|
||||
)
|
||||
|
||||
frames = inspect.getouterframes(run_frame)
|
||||
for frame in frames[2:4]:
|
||||
caller, = frame[:1]
|
||||
info = inspect.getframeinfo(caller)
|
||||
caller_module = caller.f_globals.get('__name__', '')
|
||||
|
||||
if caller_module == "setuptools.dist" and info.function == "run_command":
|
||||
# Starting from v61.0.0 setuptools overwrites dist.run_command
|
||||
continue
|
||||
|
||||
return (
|
||||
caller_module == 'distutils.dist'
|
||||
and info.function == 'run_commands'
|
||||
)
|
||||
|
||||
def do_egg_install(self):
|
||||
|
||||
|
@@ -4,6 +4,7 @@ import os
|
||||
from setuptools import Command
|
||||
from setuptools import namespaces
|
||||
from setuptools.archive_util import unpack_archive
|
||||
from .._path import ensure_directory
|
||||
import pkg_resources
|
||||
|
||||
|
||||
@@ -37,7 +38,7 @@ class install_egg_info(namespaces.Installer, Command):
|
||||
elif os.path.exists(self.target):
|
||||
self.execute(os.unlink, (self.target,), "Removing " + self.target)
|
||||
if not self.dry_run:
|
||||
pkg_resources.ensure_directory(self.target)
|
||||
ensure_directory(self.target)
|
||||
self.execute(
|
||||
self.copytree, (), "Copying %s to %s" % (self.source, self.target)
|
||||
)
|
||||
|
@@ -4,7 +4,8 @@ from distutils.errors import DistutilsModuleError
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pkg_resources import Distribution, PathMetadata, ensure_directory
|
||||
from pkg_resources import Distribution, PathMetadata
|
||||
from .._path import ensure_directory
|
||||
|
||||
|
||||
class install_scripts(orig.install_scripts):
|
||||
|
@@ -4,17 +4,19 @@ import os
|
||||
import sys
|
||||
import io
|
||||
import contextlib
|
||||
from itertools import chain
|
||||
|
||||
from .py36compat import sdist_add_defaults
|
||||
|
||||
import pkg_resources
|
||||
from .._importlib import metadata
|
||||
from .build import _ORIGINAL_SUBCOMMANDS
|
||||
|
||||
_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 ep in metadata.entry_points(group='setuptools.file_finders'):
|
||||
for item in ep.load()(dirname):
|
||||
yield item
|
||||
|
||||
@@ -31,6 +33,10 @@ class sdist(sdist_add_defaults, orig.sdist):
|
||||
('dist-dir=', 'd',
|
||||
"directory to put the source distribution archive(s) in "
|
||||
"[default: dist]"),
|
||||
('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]"),
|
||||
]
|
||||
|
||||
negative_opt = {}
|
||||
@@ -96,6 +102,10 @@ class sdist(sdist_add_defaults, orig.sdist):
|
||||
if orig_val is not NoValue:
|
||||
setattr(os, 'link', orig_val)
|
||||
|
||||
def add_defaults(self):
|
||||
super().add_defaults()
|
||||
self._add_defaults_build_sub_commands()
|
||||
|
||||
def _add_defaults_optional(self):
|
||||
super()._add_defaults_optional()
|
||||
if os.path.isfile('pyproject.toml'):
|
||||
@@ -108,14 +118,25 @@ class sdist(sdist_add_defaults, orig.sdist):
|
||||
self.filelist.extend(build_py.get_source_files())
|
||||
self._add_data_files(self._safe_data_files(build_py))
|
||||
|
||||
def _add_defaults_build_sub_commands(self):
|
||||
build = self.get_finalized_command("build")
|
||||
missing_cmds = set(build.get_sub_commands()) - _ORIGINAL_SUBCOMMANDS
|
||||
# ^-- the original built-in sub-commands are already handled by default.
|
||||
cmds = (self.get_finalized_command(c) for c in missing_cmds)
|
||||
files = (c.get_source_files() for c in cmds if hasattr(c, "get_source_files"))
|
||||
self.filelist.extend(chain.from_iterable(files))
|
||||
|
||||
def _safe_data_files(self, build_py):
|
||||
"""
|
||||
Extracting data_files from build_py is known to cause
|
||||
infinite recursion errors when `include_package_data`
|
||||
is enabled, so suppress it in that case.
|
||||
Since the ``sdist`` class is also used to compute the MANIFEST
|
||||
(via :obj:`setuptools.command.egg_info.manifest_maker`),
|
||||
there might be recursion problems when trying to obtain the list of
|
||||
data_files and ``include_package_data=True`` (which in turn depends on
|
||||
the files included in the MANIFEST).
|
||||
|
||||
To avoid that, ``manifest_maker`` should be able to overwrite this
|
||||
method and avoid recursive attempts to build/analyze the MANIFEST.
|
||||
"""
|
||||
if self.distribution.include_package_data:
|
||||
return ()
|
||||
return build_py.data_files
|
||||
|
||||
def _add_data_files(self, data_files):
|
||||
|
@@ -16,10 +16,11 @@ from pkg_resources import (
|
||||
evaluate_marker,
|
||||
add_activation_listener,
|
||||
require,
|
||||
EntryPoint,
|
||||
)
|
||||
from .._importlib import metadata
|
||||
from setuptools import Command
|
||||
from setuptools.extern.more_itertools import unique_everseen
|
||||
from setuptools.extern.jaraco.functools import pass_none
|
||||
|
||||
|
||||
class ScanningLoader(TestLoader):
|
||||
@@ -117,7 +118,7 @@ class test(Command):
|
||||
return list(self._test_args())
|
||||
|
||||
def _test_args(self):
|
||||
if not self.test_suite and sys.version_info >= (2, 7):
|
||||
if not self.test_suite:
|
||||
yield 'discover'
|
||||
if self.verbose:
|
||||
yield '--verbose'
|
||||
@@ -241,12 +242,10 @@ class test(Command):
|
||||
return ['unittest'] + self.test_args
|
||||
|
||||
@staticmethod
|
||||
@pass_none
|
||||
def _resolve_as_ep(val):
|
||||
"""
|
||||
Load the indicated attribute value, called, as a as if it were
|
||||
specified as an entry point.
|
||||
"""
|
||||
if val is None:
|
||||
return
|
||||
parsed = EntryPoint.parse("x=" + val)
|
||||
return parsed.resolve()()
|
||||
return metadata.EntryPoint(value=val, name=None, group=None).load()()
|
||||
|
@@ -17,8 +17,11 @@ import itertools
|
||||
import functools
|
||||
import http.client
|
||||
import urllib.parse
|
||||
import warnings
|
||||
|
||||
from .._importlib import metadata
|
||||
from .. import SetuptoolsDeprecationWarning
|
||||
|
||||
from pkg_resources import iter_entry_points
|
||||
from .upload import upload
|
||||
|
||||
|
||||
@@ -43,9 +46,10 @@ class upload_docs(upload):
|
||||
boolean_options = upload.boolean_options
|
||||
|
||||
def has_sphinx(self):
|
||||
if self.upload_dir is None:
|
||||
for ep in iter_entry_points('distutils.commands', 'build_sphinx'):
|
||||
return True
|
||||
return bool(
|
||||
self.upload_dir is None
|
||||
and metadata.entry_points(group='distutils.commands', name='build_sphinx')
|
||||
)
|
||||
|
||||
sub_commands = [('build_sphinx', has_sphinx)]
|
||||
|
||||
@@ -55,6 +59,9 @@ class upload_docs(upload):
|
||||
self.target_dir = None
|
||||
|
||||
def finalize_options(self):
|
||||
log.warn(
|
||||
"Upload_docs command is deprecated. Use Read the Docs "
|
||||
"(https://readthedocs.org) instead.")
|
||||
upload.finalize_options(self)
|
||||
if self.upload_dir is None:
|
||||
if self.has_sphinx():
|
||||
@@ -66,8 +73,6 @@ class upload_docs(upload):
|
||||
else:
|
||||
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.")
|
||||
self.announce('Using upload directory %s' % self.target_dir)
|
||||
|
||||
def create_zipfile(self, filename):
|
||||
@@ -87,6 +92,12 @@ class upload_docs(upload):
|
||||
zip_file.close()
|
||||
|
||||
def run(self):
|
||||
warnings.warn(
|
||||
"upload_docs is deprecated and will be removed in a future "
|
||||
"version. Use tools like httpie or curl instead.",
|
||||
SetuptoolsDeprecationWarning,
|
||||
)
|
||||
|
||||
# Run sub commands
|
||||
for cmd_name in self.get_sub_commands():
|
||||
self.run_command(cmd_name)
|
||||
|
Reference in New Issue
Block a user