[bumpversion]
-current_version = 57.5.0
+current_version = 58.0.0
commit = True
tag = True
+v58.0.0
+-------
+
+
+Breaking Changes
+^^^^^^^^^^^^^^^^
+* #2086: Removed support for 2to3 during builds. Projects should port to a unified codebase or pin to an older version of Setuptools using PEP 518 build-requires.
+
+Documentation changes
+^^^^^^^^^^^^^^^^^^^^^
+* #2746: add python_requires example
+
+
v57.5.0
-------
[build-system]
requires = ["setuptools", "wheel"]
- build-backend = "setuptools.build_meta"
+ build-backend = "setuptools.build_meta"
+
+The ``setuptools`` package implements the ``build_sdist``
+command and the ``wheel`` package implements the ``build_wheel``
+command; both are required to be compliant with PEP 517.
Use ``setuptools``' :ref:`declarative config <declarative config>` to
specify the package information::
.. class:: build_py
-.. class:: build_py_2to3
-
- Alternative implementation of build_py which also runs the
- 2to3 conversion library on each .py file that is going to be
- installed. To use this in a setup.py file for a distribution
- that is designed to run with both Python 2.x and 3.x, add::
-
- try:
- from distutils.command.build_py import build_py_2to3 as build_py
- except ImportError:
- from distutils.command.build_py import build_py
-
- to your setup.py, and later::
-
- cmdclass = {'build_py': build_py}
-
- to the invocation of setup().
-
:mod:`distutils.command.build_scripts` --- Build the scripts of a package
=========================================================================
+++ /dev/null
-=====================================================
-Supporting both Python 2 and Python 3 with Setuptools
-=====================================================
-
-Starting with Distribute version 0.6.2 and Setuptools 0.7, the Setuptools
-project supported Python 3. Installing and
-using setuptools for Python 3 code works exactly the same as for Python 2
-code.
-
-Setuptools provides a facility to invoke 2to3 on the code as a part of the
-build process, by setting the keyword parameter ``use_2to3`` to True, but
-the Setuptools project strongly recommends instead developing a unified codebase
-using `six <https://pypi.org/project/six/>`_,
-`future <https://pypi.org/project/future/>`_, or another compatibility
-library.
-
-
-Using 2to3
-==========
-
-Setuptools attempts to make the porting process easier by automatically
-running
-2to3 as a part of running tests. To do so, you need to configure the
-setup.py so that you can run the unit tests with ``python setup.py test``.
-
-See :ref:`test` for more information on this.
-
-Once you have the tests running under Python 2, you can add the use_2to3
-keyword parameters to setup(), and start running the tests under Python 3.
-The test command will now first run the build command during which the code
-will be converted with 2to3, and the tests will then be run from the build
-directory, as opposed from the source directory as is normally done.
-
-Setuptools will convert all Python files, and also all doctests in Python
-files. However, if you have doctests located in separate text files, these
-will not automatically be converted. By adding them to the
-``convert_2to3_doctests`` keyword parameter Setuptools will convert them as
-well.
-
-By default, the conversion uses all fixers in the ``lib2to3.fixers`` package.
-To use additional fixers, the parameter ``use_2to3_fixers`` can be set
-to a list of names of packages containing fixers. To exclude fixers, the
-parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be
-skipped.
-
-An example setup.py might look something like this::
-
- from setuptools import setup
-
- setup(
- name='your.module',
- version='1.0',
- description='This is your awesome module',
- author='You',
- author_email='your@email',
- package_dir={'': 'src'},
- packages=['your', 'you.module'],
- test_suite='your.module.tests',
- use_2to3=True,
- convert_2to3_doctests=['src/your/module/README.txt'],
- use_2to3_fixers=['your.fixers'],
- use_2to3_exclude_fixers=['lib2to3.fixes.fix_import'],
- )
-
-Differential conversion
------------------------
-
-Note that a file will only be copied and converted during the build process
-if the source file has been changed. If you add a file to the doctests
-that should be converted, it will not be converted the next time you run
-the tests, since it hasn't been modified. You need to remove it from the
-build directory. Also if you run the build, install or test commands before
-adding the use_2to3 parameter, you will have to remove the build directory
-before you run the test command, as the files otherwise will seem updated,
-and no conversion will happen.
-
-In general, if code doesn't seem to be converted, deleting the build directory
-and trying again is a good safeguard against the build directory getting
-"out of sync" with the source directory.
-
-Distributing Python 3 modules
-=============================
-
-You can distribute your modules with Python 3 support in different ways. A
-normal source distribution will work, but can be slow in installing, as the
-2to3 process will be run during the install. But you can also distribute
-the module in binary format, such as a binary egg. That egg will contain the
-already converted code, and hence no 2to3 conversion is needed during install.
-
-Advanced features
-=================
-
-If you don't want to run the 2to3 conversion on the doctests in Python files,
-you can turn that off by setting ``setuptools.use_2to3_on_doctests = False``.
mess with it. For more details on how this argument works, see the section
below on :ref:`Automatic Resource Extraction`.
-``use_2to3``
- Convert the source code from Python 2 to Python 3 with 2to3 during the
- build process. See :doc:`../deprecated/python3` for more details.
-
-``convert_2to3_doctests``
- List of doctest source files that need to be converted with 2to3.
- See :doc:`../deprecated/python3` for more details.
-
-``use_2to3_fixers``
- A list of modules to search for additional fixers to be used during
- the 2to3 conversion. See :doc:`../deprecated/python3` for more details.
-
-``use_2to3_exclude_fixers``
- List of fixer names to be skipped.
-
``project_urls``
An arbitrary map of URL names to hyperlinks, allowing more extensible
documentation of where various resources can be found than the simple
extras_require section [#opt-2]_
python_requires str
entry_points file:, section 51.0.0
-use_2to3 bool
-use_2to3_fixers list-comma
-use_2to3_exclude_fixers list-comma
-convert_2to3_doctests list-comma
scripts list-comma
eager_resources list-comma
dependency_links list-comma
This is handled with the ``python_requires`` keyword supplied to ``setup.cfg``
or ``setup.py``.
-Example WIP
+
+.. tab:: setup.cfg
+
+ .. code-block:: ini
+
+ [metadata]
+ name = Project-B
+ #...
+
+ [options]
+ #...
+ python_requires = >=3.6
+
+.. tab:: setup.py
+
+ .. code-block:: python
+
+ setup(
+ name="Project-B",
+ python_requires=[">=3.6"],
+ ...,
+ )
``easy-install.pth`` file to include your project's source code, thereby making
it available on ``sys.path`` for all programs using that Python installation.
-If you have enabled the ``use_2to3`` flag, then of course the ``.egg-link``
-will not link directly to your source code when run under Python 3, since
-that source code would be made for Python 2 and not work under Python 3.
-Instead the ``setup.py develop`` will build Python 3 code under the ``build``
-directory, and link there. This means that after doing code changes you will
-have to run ``setup.py build`` before these changes are picked up by your
-Python 3 installation.
-
In addition, the ``develop`` command creates wrapper scripts in the target
script directory that will run your in-development scripts after ensuring that
all your ``install_requires`` packages are available on ``sys.path``.
mess with it. For more details on how this argument works, see the section
below on :ref:`Automatic Resource Extraction`.
-``use_2to3``
- Convert the source code from Python 2 to Python 3 with 2to3 during the
- build process. See :doc:`../deprecated/python3` for more details.
-
-``convert_2to3_doctests``
- List of doctest source files that need to be converted with 2to3.
- See :doc:`../deprecated/python3` for more details.
-
-``use_2to3_fixers``
- A list of modules to search for additional fixers to be used during
- the 2to3 conversion. See :doc:`../deprecated/python3` for more details.
-
``project_urls``
An arbitrary map of URL names to hyperlinks, allowing more extensible
documentation of where various resources can be found than the simple
ignore:Parent module 'setuptools' not found while handling absolute import:RuntimeWarning
# Suppress use of bytes for filenames on Windows until fixed #2016
ignore:The Windows bytes API has been deprecated:DeprecationWarning
- # https://github.com/pypa/setuptools/issues/2081
- ignore:lib2to3 package is deprecated:PendingDeprecationWarning
- ignore:lib2to3 package is deprecated:DeprecationWarning
[metadata]
name = setuptools
-version = 57.5.0
+version = 58.0.0
author = Python Packaging Authority
author_email = distutils-sig@python.org
description = Easily download, build, install, upgrade, and uninstall Python packages
setuptools.finalize_distribution_options =
parent_finalize = setuptools.dist:_Distribution.finalize_options
keywords = setuptools.dist:Distribution._finalize_setup_keywords
- 2to3_doctests = setuptools.dist:Distribution._finalize_2to3_doctests
distutils.setup_keywords =
eager_resources = setuptools.dist:assert_string_list
namespace_packages = setuptools.dist:check_nsp
dependency_links = setuptools.dist:assert_string_list
test_loader = setuptools.dist:check_importable
test_runner = setuptools.dist:check_importable
- use_2to3 = setuptools.dist:assert_bool
- convert_2to3_doctests = setuptools.dist:assert_string_list
- use_2to3_fixers = setuptools.dist:assert_string_list
- use_2to3_exclude_fixers = setuptools.dist:assert_string_list
egg_info.writers =
PKG-INFO = setuptools.command.egg_info:write_pkg_info
requires.txt = setuptools.command.egg_info:write_requirements
__all__ = [
- 'setup', 'Distribution', 'Command', 'Extension', 'Require',
+ 'setup',
+ 'Distribution',
+ 'Command',
+ 'Extension',
+ 'Require',
'SetuptoolsDeprecationWarning',
- 'find_packages', 'find_namespace_packages',
+ 'find_packages',
+ 'find_namespace_packages',
]
__version__ = setuptools.version.__version__
bootstrap_install_from = None
-# If we run 2to3 on .py files, should we also convert docstrings?
-# Default: yes; assume that we can detect doctests reliably
-run_2to3_on_doctests = True
-# Standard package names for fixer packages
-lib2to3_fixer_packages = ['lib2to3.fixes']
-
class PackageFinder:
"""
shell style wildcard patterns just like 'exclude'.
"""
- return list(cls._find_packages_iter(
- convert_path(where),
- cls._build_filter('ez_setup', '*__pycache__', *exclude),
- cls._build_filter(*include)))
+ return list(
+ cls._find_packages_iter(
+ convert_path(where),
+ cls._build_filter('ez_setup', '*__pycache__', *exclude),
+ cls._build_filter(*include),
+ )
+ )
@classmethod
def _find_packages_iter(cls, where, exclude, include):
package = rel_path.replace(os.path.sep, '.')
# Skip directory trees that are not valid packages
- if ('.' in dir or not cls._looks_like_package(full_path)):
+ if '.' in dir or not cls._looks_like_package(full_path):
continue
# Should this package be included?
A minimal version of a distribution for supporting the
fetch_build_eggs interface.
"""
+
def __init__(self, attrs):
_incl = 'dependency_links', 'setup_requires'
- filtered = {
- k: attrs[k]
- for k in set(_incl) & set(attrs)
- }
+ filtered = {k: attrs[k] for k in set(_incl) & set(attrs)}
distutils.core.Distribution.__init__(self, filtered)
def finalize_options(self):
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_list(self, option):
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 reinitialize_command(self, command, reinit_subcommands=0, **kw):
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
from distutils.core import Command
from distutils.errors import *
-from distutils.util import convert_path, Mixin2to3
+from distutils.util import convert_path
from distutils import log
class build_py (Command):
if self.optimize > 0:
byte_compile(files, optimize=self.optimize,
force=self.force, prefix=prefix, dry_run=self.dry_run)
-
-class build_py_2to3(build_py, Mixin2to3):
- def run(self):
- self.updated_files = []
-
- # Base class code
- if self.py_modules:
- self.build_modules()
- if self.packages:
- self.build_packages()
- self.build_package_data()
-
- # 2to3
- self.run_2to3(self.updated_files)
-
- # Remaining base class code
- self.byte_compile(self.get_outputs(include_bytecode=0))
-
- def build_module(self, module, module_file, package):
- res = build_py.build_module(self, module, module_file, package)
- if res[1]:
- # file was copied
- self.updated_files.append(res[0])
- return res
from distutils import sysconfig
from distutils.core import Command
from distutils.dep_util import newer
-from distutils.util import convert_path, Mixin2to3
+from distutils.util import convert_path
from distutils import log
import tokenize
os.chmod(file, newmode)
# XXX should we modify self.outfiles?
return outfiles, updated_files
-
-class build_scripts_2to3(build_scripts, Mixin2to3):
-
- def copy_scripts(self):
- outfiles, updated_files = build_scripts.copy_scripts(self)
- if not self.dry_run:
- self.run_2to3(updated_files)
- return outfiles, updated_files
lines = header.split('\n')
sep = '\n' + 8 * ' '
return sep.join(lines)
-
-# 2to3 support
-
-def run_2to3(files, fixer_names=None, options=None, explicit=None):
- """Invoke 2to3 on a list of Python files.
- The files should all come from the build area, as the
- modification is done in-place. To reduce the build time,
- only files modified since the last invocation of this
- function should be passed in the files argument."""
-
- if not files:
- return
-
- # Make this class local, to delay import of 2to3
- from lib2to3.refactor import RefactoringTool, get_fixers_from_package
- class DistutilsRefactoringTool(RefactoringTool):
- def log_error(self, msg, *args, **kw):
- log.error(msg, *args)
-
- def log_message(self, msg, *args):
- log.info(msg, *args)
-
- def log_debug(self, msg, *args):
- log.debug(msg, *args)
-
- if fixer_names is None:
- fixer_names = get_fixers_from_package('lib2to3.fixes')
- r = DistutilsRefactoringTool(fixer_names, options=options)
- r.refactor(files, write=True)
-
-def copydir_run_2to3(src, dest, template=None, fixer_names=None,
- options=None, explicit=None):
- """Recursively copy a directory, only copying new and changed files,
- running run_2to3 over all newly copied Python modules afterward.
-
- If you give a template string, it's parsed like a MANIFEST.in.
- """
- from distutils.dir_util import mkpath
- from distutils.file_util import copy_file
- from distutils.filelist import FileList
- filelist = FileList()
- curdir = os.getcwd()
- os.chdir(src)
- try:
- filelist.findall()
- finally:
- os.chdir(curdir)
- filelist.files[:] = filelist.allfiles
- if template:
- for line in template.splitlines():
- line = line.strip()
- if not line: continue
- filelist.process_template_line(line)
- copied = []
- for filename in filelist.files:
- outname = os.path.join(dest, filename)
- mkpath(os.path.dirname(outname))
- res = copy_file(os.path.join(src, filename), outname, update=1)
- if res[1]: copied.append(outname)
- run_2to3([fn for fn in copied if fn.lower().endswith('.py')],
- fixer_names=fixer_names, options=options, explicit=explicit)
- return copied
-
-class Mixin2to3:
- '''Mixin class for commands that run 2to3.
- To configure 2to3, setup scripts may either change
- the class variables, or inherit from individual commands
- to override how 2to3 is invoked.'''
-
- # provide list of fixers to run;
- # defaults to all from lib2to3.fixers
- fixer_names = None
-
- # options dictionary
- options = None
-
- # list of fixers to invoke even though they are marked as explicit
- explicit = None
-
- def run_2to3(self, files):
- return run_2to3(files, self.fixer_names, self.options, self.explicit)
import stat
from setuptools.extern.more_itertools import unique_everseen
-try:
- from setuptools.lib2to3_ex import Mixin2to3
-except Exception:
-
- class Mixin2to3:
- def run_2to3(self, files, doctests=True):
- "do nothing"
-
def make_writable(target):
os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE)
-class build_py(orig.build_py, Mixin2to3):
+class build_py(orig.build_py):
"""Enhanced 'build_py' command that includes data files with packages
The data files are specified via a 'package_data' argument to 'setup()'.
def finalize_options(self):
orig.build_py.finalize_options(self)
self.package_data = self.distribution.package_data
- self.exclude_package_data = (self.distribution.exclude_package_data or
- {})
+ self.exclude_package_data = self.distribution.exclude_package_data or {}
if 'data_files' in self.__dict__:
del self.__dict__['data_files']
self.__updated_files = []
- self.__doctests_2to3 = []
def run(self):
"""Build modules, packages, and copy data files to build directory"""
self.build_packages()
self.build_package_data()
- self.run_2to3(self.__updated_files, False)
- self.run_2to3(self.__updated_files, True)
- self.run_2to3(self.__doctests_2to3, True)
-
# Only compile actual .py files, using our base class' idea of what our
# output files are.
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
return orig.build_py.__getattr__(self, attr)
def build_module(self, module, module_file, package):
- outfile, copied = orig.build_py.build_module(self, module, module_file,
- package)
+ outfile, copied = orig.build_py.build_module(self, module, module_file, package)
if copied:
self.__updated_files.append(outfile)
return outfile, copied
outf, copied = self.copy_file(srcfile, target)
make_writable(target)
srcfile = os.path.abspath(srcfile)
- if (copied and
- srcfile in self.distribution.convert_2to3_doctests):
- self.__doctests_2to3.append(outf)
def analyze_manifest(self):
self.manifest_files = mf = {}
package,
src_dir,
)
- match_groups = (
- fnmatch.filter(files, pattern)
- for pattern in patterns
- )
+ match_groups = (fnmatch.filter(files, pattern) for pattern in patterns)
# flatten the groups of matches into an iterable of matches
matches = itertools.chain.from_iterable(match_groups)
bad = set(matches)
- keepers = (
- fn
- for fn in files
- if fn not in bad
- )
+ keepers = (fn for fn in files if fn not in bad)
# ditch dupes
return list(unique_everseen(keepers))
return path
from distutils.errors import DistutilsSetupError
- msg = textwrap.dedent("""
+ msg = (
+ textwrap.dedent(
+ """
Error: setup script specifies an absolute path:
%s
setup() arguments must *always* be /-separated paths relative to the
setup.py directory, *never* absolute paths.
- """).lstrip() % path
+ """
+ ).lstrip()
+ % path
+ )
raise DistutilsSetupError(msg)
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"
self.dist = pkg_resources.Distribution(
target,
pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)),
- project_name=ei.egg_name
+ project_name=ei.egg_name,
)
self.setup_path = self._resolve_setup_path(
if resolved != pkg_resources.normalize_path(os.curdir):
raise DistutilsOptionError(
"Can't get a consistent path to setup script from"
- " installation directory", resolved,
- pkg_resources.normalize_path(os.curdir))
+ " installation directory",
+ resolved,
+ pkg_resources.normalize_path(os.curdir),
+ )
return path_to_setup
def install_for_development(self):
- if getattr(self.distribution, 'use_2to3', False):
- # If we run 2to3 we can not do this inplace:
-
- # Ensure metadata is up-to-date
- self.reinitialize_command('build_py', inplace=0)
- self.run_command('build_py')
- bpy_cmd = self.get_finalized_command("build_py")
- build_path = pkg_resources.normalize_path(bpy_cmd.build_lib)
-
- # Build extensions
- self.reinitialize_command('egg_info', egg_base=build_path)
- self.run_command('egg_info')
-
- self.reinitialize_command('build_ext', inplace=0)
- self.run_command('build_ext')
-
- # Fixup egg-link and easy-install.pth
- ei_cmd = self.get_finalized_command("egg_info")
- self.egg_path = build_path
- self.dist.location = build_path
- # XXX
- self.dist._provider = pkg_resources.PathMetadata(
- build_path, ei_cmd.egg_info)
- else:
- # Without 2to3 inplace works fine:
- self.run_command('egg_info')
+ self.run_command('egg_info')
- # Build extensions in-place
- self.reinitialize_command('build_ext', inplace=1)
- self.run_command('build_ext')
+ # Build extensions in-place
+ self.reinitialize_command('build_ext', inplace=1)
+ self.run_command('build_ext')
if setuptools.bootstrap_install_from:
self.easy_install(setuptools.bootstrap_install_from)
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]):
+ if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
log.warn("Link points to %s: uninstall aborted", contents)
return
if not self.dry_run:
from distutils import log
from unittest import TestLoader
-from pkg_resources import (resource_listdir, resource_exists, normalize_path,
- working_set, _namespace_packages, evaluate_marker,
- add_activation_listener, require, EntryPoint)
+from pkg_resources import (
+ resource_listdir,
+ resource_exists,
+ normalize_path,
+ working_set,
+ evaluate_marker,
+ add_activation_listener,
+ require,
+ EntryPoint,
+)
from setuptools import Command
from setuptools.extern.more_itertools import unique_everseen
class ScanningLoader(TestLoader):
-
def __init__(self):
TestLoader.__init__(self)
self._visited = set()
user_options = [
('test-module=', 'm', "Run 'test_suite' in specified module"),
- ('test-suite=', 's',
- "Run single test, case or suite (e.g. 'module.test_suite')"),
+ (
+ 'test-suite=',
+ 's',
+ "Run single test, case or suite (e.g. 'module.test_suite')",
+ ),
('test-runner=', 'r', "Test runner to use"),
]
@contextlib.contextmanager
def project_on_sys_path(self, include_dists=[]):
- with_2to3 = getattr(self.distribution, 'use_2to3', False)
-
- if with_2to3:
- # If we run 2to3 we can not do this inplace:
+ self.run_command('egg_info')
- # Ensure metadata is up-to-date
- self.reinitialize_command('build_py', inplace=0)
- self.run_command('build_py')
- bpy_cmd = self.get_finalized_command("build_py")
- build_path = normalize_path(bpy_cmd.build_lib)
-
- # Build extensions
- self.reinitialize_command('egg_info', egg_base=build_path)
- self.run_command('egg_info')
-
- self.reinitialize_command('build_ext', inplace=0)
- self.run_command('build_ext')
- else:
- # Without 2to3 inplace works fine:
- self.run_command('egg_info')
-
- # Build extensions in-place
- self.reinitialize_command('build_ext', inplace=1)
- self.run_command('build_ext')
+ # Build extensions in-place
+ self.reinitialize_command('build_ext', inplace=1)
+ self.run_command('build_ext')
ei_cmd = self.get_finalized_command("egg_info")
ir_d = dist.fetch_build_eggs(dist.install_requires)
tr_d = dist.fetch_build_eggs(dist.tests_require or [])
er_d = dist.fetch_build_eggs(
- v for k, v in dist.extras_require.items()
+ v
+ for k, v in dist.extras_require.items()
if k.startswith(':') and evaluate_marker(k[1:])
)
return itertools.chain(ir_d, tr_d, er_d)
self.run_tests()
def run_tests(self):
- # Purge modules under test from sys.modules. The test loader will
- # re-import them from the build location. Required when 2to3 is used
- # with namespace packages.
- if getattr(self.distribution, 'use_2to3', False):
- module = self.test_suite.split('.')[0]
- if module in _namespace_packages:
- del_modules = []
- if module in sys.modules:
- del_modules.append(module)
- module += '.'
- for name in sys.modules:
- if name.startswith(module):
- del_modules.append(name)
- list(map(sys.modules.__delitem__, del_modules))
-
test = unittest.main(
- None, None, self._argv,
+ None,
+ None,
+ self._argv,
testLoader=self._resolve_as_ep(self.test_loader),
testRunner=self._resolve_as_ep(self.test_runner),
exit=False,
"""
Attempt to load the module by the name
"""
+
def __init__(self, name):
spec = importlib.util.find_spec(name)
with open(spec.origin) as strm:
sys.path.remove(path)
-def read_configuration(
- filepath, find_others=False, ignore_option_errors=False):
+def read_configuration(filepath, find_others=False, ignore_option_errors=False):
"""Read given configuration file and returns options from it as a dict.
:param str|unicode filepath: Path to configuration file
filepath = os.path.abspath(filepath)
if not os.path.isfile(filepath):
- raise DistutilsFileError(
- 'Configuration file %s does not exist.' % filepath)
+ raise DistutilsFileError('Configuration file %s does not exist.' % filepath)
current_directory = os.getcwd()
os.chdir(os.path.dirname(filepath))
_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:
os.chdir(current_directory)
return config_dict
-def parse_configuration(
- distribution, command_options, ignore_option_errors=False):
+def parse_configuration(distribution, command_options, ignore_option_errors=False):
"""Performs additional parsing of configuration options
for a distribution.
If False exceptions are propagated as expected.
:rtype: list
"""
- options = ConfigOptionsHandler(
- distribution, command_options, ignore_option_errors)
+ options = ConfigOptionsHandler(distribution, command_options, ignore_option_errors)
options.parse()
meta = ConfigMetadataHandler(
- distribution.metadata, command_options, ignore_option_errors,
- distribution.package_dir)
+ distribution.metadata,
+ command_options,
+ ignore_option_errors,
+ distribution.package_dir,
+ )
meta.parse()
return meta, options
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):
unknown = tuple()
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()
return result
:param key:
:rtype: callable
"""
+
def parser(value):
exclude_directive = 'file:'
if value.startswith(exclude_directive):
raise ValueError(
'Only strings are accepted for the {0} field, '
- 'files are not accepted'.format(key))
+ 'files are not accepted'.format(key)
+ )
return value
+
return parser
@classmethod
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)
for path in filepaths
- if (cls._assert_local(path) or True)
- and os.path.isfile(path)
+ if (cls._assert_local(path) or True) and os.path.isfile(path)
)
@staticmethod
def _assert_local(filepath):
if not filepath.startswith(os.getcwd()):
- raise DistutilsOptionError(
- '`file:` directive can not access %s' % filepath)
+ raise DistutilsOptionError('`file:` directive can not access %s' % filepath)
@staticmethod
def _read_file(filepath):
:param parse_methods:
:rtype: callable
"""
+
def parse(value):
parsed = value
self,
# Dots in section names are translated into dunderscores.
('parse_section%s' % method_postfix).replace('.', '__'),
- None)
+ None,
+ )
if section_parser_method is None:
raise DistutilsOptionError(
- 'Unsupported distribution option section: [%s.%s]' % (
- self.section_prefix, section_name))
+ 'Unsupported distribution option section: [%s.%s]'
+ % (self.section_prefix, section_name)
+ )
section_parser_method(section_options)
def _deprecated_config_handler(self, func, msg, warning_class):
- """ this function will wrap around parameters that are deprecated
+ """this function will wrap around parameters that are deprecated
:param msg: deprecation message
:param warning_class: class of warning exception to be raised
:param func: function to be wrapped around
"""
+
@wraps(func)
def config_handler(*args, **kwargs):
warnings.warn(msg, warning_class)
"""
- def __init__(self, target_obj, options, ignore_option_errors=False,
- package_dir=None):
- super(ConfigMetadataHandler, self).__init__(target_obj, options,
- ignore_option_errors)
+ def __init__(
+ self, target_obj, options, ignore_option_errors=False, package_dir=None
+ ):
+ super(ConfigMetadataHandler, self).__init__(
+ target_obj, options, ignore_option_errors
+ )
self.package_dir = package_dir
@property
parse_list,
"The requires parameter is deprecated, please use "
"install_requires for runtime dependencies.",
- DeprecationWarning),
+ DeprecationWarning,
+ ),
'obsoletes': parse_list,
'classifiers': self._get_parser_compound(parse_file, parse_list),
'license': exclude_files_parser('license'),
exclude_files_parser('license_file'),
"The license_file parameter is deprecated, "
"use license_files instead.",
- DeprecationWarning),
+ DeprecationWarning,
+ ),
'license_files': parse_list,
'description': parse_file,
'long_description': parse_file,
return {
'zip_safe': parse_bool,
- 'use_2to3': parse_bool,
'include_package_data': parse_bool,
'package_dir': parse_dict,
- 'use_2to3_fixers': parse_list,
- 'use_2to3_exclude_fixers': parse_list,
- 'convert_2to3_doctests': parse_list,
'scripts': parse_list,
'eager_resources': parse_list,
'dependency_links': parse_list,
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)
return getattr(module, class_name)
- return {
- k: resolve_class(v)
- for k, v in self._parse_dict(value).items()
- }
+ return {k: resolve_class(v) for k, v in self._parse_dict(value).items()}
def _parse_packages(self, value):
"""Parses `packages` option value.
# 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:
from setuptools import find_namespace_packages as find_packages
:param dict section_options:
"""
- section_data = self._parse_section_to_dict(
- section_options, self._parse_list)
+ section_data = self._parse_section_to_dict(section_options, self._parse_list)
valid_keys = ['where', 'include', 'exclude']
find_kwargs = dict(
- [(k, v) for k, v in section_data.items() if k in valid_keys and v])
+ [(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:
:param dict section_options:
"""
- self['exclude_package_data'] = self._parse_package_data(
- section_options)
+ self['exclude_package_data'] = self._parse_package_data(section_options)
def parse_section_extras_require(self, section_options):
"""Parses `extras_require` configuration file section.
"""
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):
"""Parses `data_files` configuration file section.
lines = content.splitlines()
if len(lines) == 1:
return lines[0].lstrip()
- return '\n'.join(
- (lines[0].lstrip(),
- textwrap.dedent('\n'.join(lines[1:]))))
+ return '\n'.join((lines[0].lstrip(), textwrap.dedent('\n'.join(lines[1:]))))
def _read_field_from_msg(msg: "Message", field: str) -> Optional[str]:
# Based on Python 3.5 version
def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME
- """Write the PKG-INFO format data to a file object.
- """
+ """Write the PKG-INFO format data to a file object."""
version = self.get_metadata_version()
def write_field(key, value):
# PEP 566
if self.long_description_content_type:
- write_field(
- 'Description-Content-Type',
- self.long_description_content_type
- )
+ write_field('Description-Content-Type', self.long_description_content_type)
if self.provides_extras:
for extra in self.provides_extras:
write_field('Provides-Extra', extra)
assert not ep.extras
except (TypeError, ValueError, AttributeError, AssertionError) as e:
raise DistutilsSetupError(
- "%r must be importable 'module:attrs' string (got %r)"
- % (attr, value)
+ "%r must be importable 'module:attrs' string (got %r)" % (attr, value)
) from e
for nsp in ns_packages:
if not dist.has_contents_for(nsp):
raise DistutilsSetupError(
- "Distribution contains no modules or packages for " +
- "namespace package %r" % nsp
+ "Distribution contains no modules or packages for "
+ + "namespace package %r" % nsp
)
parent, sep, child = nsp.rpartition('.')
if parent and parent not in ns_packages:
distutils.log.warn(
"WARNING: %r is declared as a package namespace, but %r"
- " is not: please correct this in setup.py", nsp, parent
+ " is not: please correct this in setup.py",
+ nsp,
+ parent,
)
"{attr!r} must be a string or list of strings "
"containing valid project/version requirement specifiers; {error}"
)
- raise DistutilsSetupError(
- tmpl.format(attr=attr, error=error)
- ) from error
+ raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error
def check_specifier(dist, attr, value):
packaging.specifiers.SpecifierSet(value)
except (packaging.specifiers.InvalidSpecifier, AttributeError) as error:
tmpl = (
- "{attr!r} must be a string "
- "containing valid version specifiers; {error}"
+ "{attr!r} must be a string " "containing valid version specifiers; {error}"
)
- raise DistutilsSetupError(
- tmpl.format(attr=attr, error=error)
- ) from error
+ raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) from error
def check_entry_points(dist, attr, value):
if not isinstance(value, dict):
raise DistutilsSetupError(
"{!r} must be a dictionary mapping package names to lists of "
- "string wildcard patterns".format(attr))
+ "string wildcard patterns".format(attr)
+ )
for k, v in value.items():
if not isinstance(k, str):
raise DistutilsSetupError(
- "keys of {!r} dict must be strings (got {!r})"
- .format(attr, k)
+ "keys of {!r} dict must be strings (got {!r})".format(attr, k)
)
assert_string_list(dist, 'values of {!r} dict'.format(attr), v)
if not re.match(r'\w+(\.\w+)*', pkgname):
distutils.log.warn(
"WARNING: %r not a valid package name; please use only "
- ".-separated package names in setup.py", pkgname
+ ".-separated package names in setup.py",
+ pkgname,
)
self.setup_requires = attrs.pop('setup_requires', [])
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
vars(self).setdefault(ep.name, None)
- _Distribution.__init__(self, {
- k: v for k, v in attrs.items()
- if k not in self._DISTUTILS_UNSUPPORTED_METADATA
- })
+ _Distribution.__init__(
+ self,
+ {
+ k: v
+ for k, v in attrs.items()
+ if k not in self._DISTUTILS_UNSUPPORTED_METADATA
+ },
+ )
self._set_metadata_defaults(attrs)
self.metadata.version = self._normalize_version(
- self._validate_version(self.metadata.version))
+ self._validate_version(self.metadata.version)
+ )
self._finalize_requires()
def _set_metadata_defaults(self, attrs):
patterns = ('LICEN[CS]E*', 'COPYING*', 'NOTICE*', 'AUTHORS*')
self.metadata.license_files = list(
- unique_everseen(self._expand_patterns(patterns)))
+ unique_everseen(self._expand_patterns(patterns))
+ )
@staticmethod
def _expand_patterns(patterns):
path
for pattern in patterns
for path in sorted(iglob(pattern))
- if not path.endswith('~')
- and os.path.isfile(path)
+ if not path.endswith('~') and os.path.isfile(path)
)
# FIXME: 'Distribution._parse_config_files' is too complex (14)
from configparser import ConfigParser
# Ignore install directory options if we have a venv
- ignore_options = [] if sys.prefix == sys.base_prefix else [
- 'install-base', 'install-platbase', 'install-lib',
- 'install-platlib', 'install-purelib', 'install-headers',
- 'install-scripts', 'install-data', 'prefix', 'exec-prefix',
- 'home', 'user', 'root',
- ]
+ ignore_options = (
+ []
+ if sys.prefix == sys.base_prefix
+ else [
+ 'install-base',
+ 'install-platbase',
+ 'install-lib',
+ 'install-platlib',
+ 'install-purelib',
+ 'install-headers',
+ 'install-scripts',
+ 'install-data',
+ 'prefix',
+ 'exec-prefix',
+ 'home',
+ 'user',
+ 'root',
+ ]
+ )
ignore_options = frozenset(ignore_options)
def warn_dash_deprecation(self, opt, section):
if section in (
- 'options.extras_require', 'options.data_files',
+ 'options.extras_require',
+ 'options.data_files',
):
return opt
underscore_opt = opt.replace('-', '_')
commands = distutils.command.__all__ + self._setuptools_commands()
- if (not section.startswith('options') and section != 'metadata'
- and section not in commands):
+ if (
+ not section.startswith('options')
+ and section != 'metadata'
+ and section not in commands
+ ):
return underscore_opt
if '-' in opt:
warnings.warn(
"Usage of dash-separated '%s' will not be supported in future "
"versions. Please use the underscore name '%s' instead"
- % (opt, underscore_opt))
+ % (opt, underscore_opt)
+ )
return underscore_opt
def _setuptools_commands(self):
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(" %s = %s (from %s)" % (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:
else:
raise DistutilsOptionError(
"error in %s: command '%s' has no such option '%s'"
- % (source, command_name, option))
+ % (source, command_name, option)
+ )
except ValueError as e:
raise DistutilsOptionError(e) from e
"""
self._parse_config_files(filenames=filenames)
- parse_configuration(self, self.command_options,
- ignore_option_errors=ignore_option_errors)
+ parse_configuration(
+ self, self.command_options, ignore_option_errors=ignore_option_errors
+ )
self._finalize_requires()
self._finalize_license_files()
def by_order(hook):
return getattr(hook, 'order', 0)
+
eps = map(lambda e: e.load(), pkg_resources.iter_entry_points(group))
for ep in sorted(eps, key=by_order):
ep(self)
ep.require(installer=self.fetch_build_egg)
ep.load()(self, ep.name, value)
- def _finalize_2to3_doctests(self):
- if getattr(self, 'convert_2to3_doctests', None):
- # XXX may convert to set here when we can rely on set being builtin
- self.convert_2to3_doctests = [
- os.path.abspath(p)
- for p in self.convert_2to3_doctests
- ]
- else:
- self.convert_2to3_doctests = []
-
def get_egg_cache_dir(self):
egg_cache_dir = os.path.join(os.curdir, '.eggs')
if not os.path.exists(egg_cache_dir):
windows_support.hide_file(egg_cache_dir)
readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt')
with open(readme_txt_filename, 'w') as f:
- f.write('This directory contains eggs that were downloaded '
- 'by setuptools to build, test, and run plug-ins.\n\n')
- f.write('This directory caches those eggs to prevent '
- 'repeated downloads.\n\n')
+ f.write(
+ 'This directory contains eggs that were downloaded '
+ 'by setuptools to build, test, and run plug-ins.\n\n'
+ )
+ f.write(
+ 'This directory caches those eggs to prevent '
+ 'repeated downloads.\n\n'
+ )
f.write('However, it is safe to delete this directory.\n\n')
return egg_cache_dir
def fetch_build_egg(self, req):
"""Fetch an egg needed for building"""
from setuptools.installer import fetch_build_egg
+
return fetch_build_egg(self, req)
def get_command_class(self, command):
pfx = package + '.'
if self.packages:
self.packages = [
- p for p in self.packages
- if p != package and not p.startswith(pfx)
+ p for p in self.packages if p != package and not p.startswith(pfx)
]
if self.py_modules:
self.py_modules = [
- p for p in self.py_modules
- if p != package and not p.startswith(pfx)
+ p for p in self.py_modules if p != package and not p.startswith(pfx)
]
if self.ext_modules:
self.ext_modules = [
- p for p in self.ext_modules
+ p
+ for p in self.ext_modules
if p.name != package and not p.name.startswith(pfx)
]
try:
old = getattr(self, name)
except AttributeError as e:
- raise DistutilsSetupError(
- "%s: No such distribution setting" % name
- ) from e
+ raise DistutilsSetupError("%s: No such distribution setting" % name) from e
if old is not None and not isinstance(old, sequence):
raise DistutilsSetupError(
name + ": this setting cannot be changed via include/exclude"
"""Handle 'include()' for list/tuple attrs without a special handler"""
if not isinstance(value, sequence):
- raise DistutilsSetupError(
- "%s: setting must be a list (%r)" % (name, value)
- )
+ raise DistutilsSetupError("%s: setting must be a list (%r)" % (name, value))
try:
old = getattr(self, name)
except AttributeError as e:
- raise DistutilsSetupError(
- "%s: No such distribution setting" % name
- ) from e
+ raise DistutilsSetupError("%s: No such distribution setting" % name) from e
if old is None:
setattr(self, name, value)
elif not isinstance(old, sequence):
src, alias = aliases[command]
del aliases[command] # ensure each alias can expand only once!
import shlex
+
args[:1] = shlex.split(alias, True)
command = args[0]
line_buffering = sys.stdout.line_buffering
sys.stdout = io.TextIOWrapper(
- sys.stdout.detach(), 'utf-8', errors, newline, line_buffering)
+ sys.stdout.detach(), 'utf-8', errors, newline, line_buffering
+ )
try:
return _Distribution.handle_display_options(self, option_order)
finally:
sys.stdout = io.TextIOWrapper(
- sys.stdout.detach(), encoding, errors, newline, line_buffering)
+ sys.stdout.detach(), encoding, errors, newline, line_buffering
+ )
class DistDeprecationWarning(SetuptoolsDeprecationWarning):
+++ /dev/null
-"""
-Customized Mixin2to3 support:
-
- - adds support for converting doctests
-"""
-
-import warnings
-from distutils.util import Mixin2to3 as _Mixin2to3
-from distutils import log
-from lib2to3.refactor import RefactoringTool, get_fixers_from_package
-
-import setuptools
-from ._deprecation_warning import SetuptoolsDeprecationWarning
-
-
-class DistutilsRefactoringTool(RefactoringTool):
- def log_error(self, msg, *args, **kw):
- log.error(msg, *args)
-
- def log_message(self, msg, *args):
- log.info(msg, *args)
-
- def log_debug(self, msg, *args):
- log.debug(msg, *args)
-
-
-class Mixin2to3(_Mixin2to3):
- def run_2to3(self, files, doctests=False):
- # See of the distribution option has been set, otherwise check the
- # setuptools default.
- if self.distribution.use_2to3 is not True:
- return
- if not files:
- return
-
- warnings.warn(
- "2to3 support is deprecated. If the project still "
- "requires Python 2 support, please migrate to "
- "a single-codebase solution or employ an "
- "independent conversion process.",
- SetuptoolsDeprecationWarning)
- log.info("Fixing " + " ".join(files))
- self.__build_fixer_names()
- self.__exclude_fixers()
- if doctests:
- if setuptools.run_2to3_on_doctests:
- r = DistutilsRefactoringTool(self.fixer_names)
- r.refactor(files, write=True, doctests_only=True)
- else:
- _Mixin2to3.run_2to3(self, files)
-
- def __build_fixer_names(self):
- if self.fixer_names:
- return
- self.fixer_names = []
- for p in setuptools.lib2to3_fixer_packages:
- self.fixer_names.extend(get_fixers_from_package(p))
- if self.distribution.use_2to3_fixers is not None:
- for p in self.distribution.use_2to3_fixers:
- self.fixer_names.extend(get_fixers_from_package(p))
-
- def __exclude_fixers(self):
- excluded_fixers = getattr(self, 'exclude_fixers', [])
- if self.distribution.use_2to3_exclude_fixers is not None:
- excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers)
- for fixer_name in excluded_fixers:
- if fixer_name in self.fixer_names:
- self.fixer_names.remove(fixer_name)
__all__ = [
- "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
+ "AbstractSandbox",
+ "DirectorySandbox",
+ "SandboxViolation",
+ "run_setup",
]
except Exception:
# get UnpickleableException inside the sandbox
from setuptools.sandbox import UnpickleableException as cls
+
return cls.dump(cls, cls(repr(exc)))
sys.modules.update(saved)
# remove any modules imported since
del_modules = (
- mod_name for mod_name in sys.modules
+ mod_name
+ for mod_name in sys.modules
if mod_name not in saved
# exclude any encodings modules. See #285
and not mod_name.startswith('encodings.')
def __init__(self):
self._attrs = [
- name for name in dir(_os)
+ name
+ for name in dir(_os)
if not name.startswith('_') and hasattr(self, name)
]
_file = _mk_single_path_wrapper('file', _file)
_open = _mk_single_path_wrapper('open', _open)
for name in [
- "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir",
- "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat",
- "startfile", "mkfifo", "mknod", "pathconf", "access"
+ "stat",
+ "listdir",
+ "chdir",
+ "open",
+ "chmod",
+ "chown",
+ "mkdir",
+ "remove",
+ "unlink",
+ "rmdir",
+ "utime",
+ "lchown",
+ "chroot",
+ "lstat",
+ "startfile",
+ "mkfifo",
+ "mknod",
+ "pathconf",
+ "access",
]:
if hasattr(_os, name):
locals()[name] = _mk_single_path_wrapper(name)
"""Called for path pairs like rename, link, and symlink operations"""
return (
self._remap_input(operation + '-from', src, *args, **kw),
- self._remap_input(operation + '-to', dst, *args, **kw)
+ self._remap_input(operation + '-to', dst, *args, **kw),
)
class DirectorySandbox(AbstractSandbox):
"""Restrict operations to a single subdirectory - pseudo-chroot"""
- write_ops = dict.fromkeys([
- "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir",
- "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam",
- ])
+ write_ops = dict.fromkeys(
+ [
+ "open",
+ "chmod",
+ "chown",
+ "mkdir",
+ "remove",
+ "unlink",
+ "rmdir",
+ "utime",
+ "lchown",
+ "chroot",
+ "mkfifo",
+ "mknod",
+ "tempnam",
+ ]
+ )
- _exception_patterns = [
- # Allow lib2to3 to attempt to save a pickled grammar object (#121)
- r'.*lib2to3.*\.pickle$',
- ]
+ _exception_patterns = []
"exempt writing to paths that match the pattern"
def __init__(self, sandbox, exceptions=_EXCEPTIONS):
self._sandbox = os.path.normcase(os.path.realpath(sandbox))
self._prefix = os.path.join(self._sandbox, '')
self._exceptions = [
- os.path.normcase(os.path.realpath(path))
- for path in exceptions
+ os.path.normcase(os.path.realpath(path)) for path in exceptions
]
AbstractSandbox.__init__(self)
def _violation(self, operation, *args, **kw):
from setuptools.sandbox import SandboxViolation
+
raise SandboxViolation(operation, args, kw)
if _file:
def _exempted(self, filepath):
start_matches = (
- filepath.startswith(exception)
- for exception in self._exceptions
+ filepath.startswith(exception) for exception in self._exceptions
)
pattern_matches = (
- re.match(pattern, filepath)
- for pattern in self._exception_patterns
+ re.match(pattern, filepath) for pattern in self._exception_patterns
)
candidates = itertools.chain(start_matches, pattern_matches)
return any(candidates)
WRITE_FLAGS = functools.reduce(
- operator.or_, [
- getattr(_os, a, 0) for a in
- "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()]
+ operator.or_,
+ [
+ getattr(_os, a, 0)
+ for a in "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()
+ ],
)
class SandboxViolation(DistutilsError):
"""A setup script attempted to modify the filesystem outside the sandbox"""
- tmpl = textwrap.dedent("""
+ tmpl = textwrap.dedent(
+ """
SandboxViolation: {cmd}{args!r} {kwargs}
The package setup script has attempted to modify files on your system
support alternate installation locations even if you run its setup
script by hand. Please inform the package's author and the EasyInstall
maintainers to find out if a fix or workaround is available.
- """).lstrip()
+ """
+ ).lstrip()
def __str__(self):
cmd, args, kwargs = self.args
import pytest
-__all__ = ['fail_on_ascii', 'ack_2to3']
+__all__ = ['fail_on_ascii']
is_ascii = locale.getpreferredencoding() == 'ANSI_X3.4-1968'
fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale")
-
-
-ack_2to3 = pytest.mark.filterwarnings('ignore:2to3 support is deprecated')
def fake_env(
- tmpdir, setup_cfg, setup_py=None,
- encoding='ascii', package_path='fake_package'):
+ tmpdir, setup_cfg, setup_py=None, encoding='ascii', package_path='fake_package'
+):
if setup_py is None:
- setup_py = (
- 'from setuptools import setup\n'
- 'setup()\n'
- )
+ setup_py = 'from setuptools import setup\n' 'setup()\n'
tmpdir.join('setup.py').write(setup_py)
config = tmpdir.join('setup.cfg')
class TestConfigurationReader:
-
def test_basic(self, tmpdir):
_, config = fake_env(
tmpdir,
'keywords = one, two\n'
'\n'
'[options]\n'
- 'scripts = bin/a.py, bin/b.py\n'
+ 'scripts = bin/a.py, bin/b.py\n',
)
config_dict = read_configuration('%s' % config)
assert config_dict['metadata']['version'] == '10.1.1'
def test_ignore_errors(self, tmpdir):
_, config = fake_env(
tmpdir,
- '[metadata]\n'
- 'version = attr: none.VERSION\n'
- 'keywords = one, two\n'
+ '[metadata]\n' 'version = attr: none.VERSION\n' 'keywords = one, two\n',
)
with pytest.raises(ImportError):
read_configuration('%s' % config)
- config_dict = read_configuration(
- '%s' % config, ignore_option_errors=True)
+ config_dict = read_configuration('%s' % config, ignore_option_errors=True)
assert config_dict['metadata']['keywords'] == ['one', 'two']
assert 'version' not in config_dict['metadata']
class TestMetadata:
-
def test_basic(self, tmpdir):
fake_env(
'provides = package, package.sub\n'
'license = otherlic\n'
'download_url = http://test.test.com/test/\n'
- 'maintainer_email = test@test.com\n'
+ 'maintainer_email = test@test.com\n',
)
tmpdir.join('README').write('readme contents\nline2')
def test_license_cfg(self, tmpdir):
fake_env(
tmpdir,
- DALS("""
+ DALS(
+ """
[metadata]
name=foo
version=0.0.1
license=Apache 2.0
- """)
+ """
+ ),
)
with get_dist(tmpdir) as dist:
fake_env(
tmpdir,
- '[metadata]\n'
- 'long_description = file: README.rst, CHANGES.rst\n'
- '\n'
+ '[metadata]\n' 'long_description = file: README.rst, CHANGES.rst\n' '\n',
)
tmpdir.join('README.rst').write('readme contents\nline2')
with get_dist(tmpdir) as dist:
assert dist.metadata.long_description == (
- 'readme contents\nline2\n'
- 'changelog contents\nand stuff'
+ 'readme contents\nline2\n' 'changelog contents\nand stuff'
)
def test_file_sandboxed(self, tmpdir):
- fake_env(
- tmpdir,
- '[metadata]\n'
- 'long_description = file: ../../README\n'
- )
+ fake_env(tmpdir, '[metadata]\n' 'long_description = file: ../../README\n')
with get_dist(tmpdir, parse=False) as dist:
with pytest.raises(DistutilsOptionError):
'platform = a, b\n'
'classifier =\n'
' Framework :: Django\n'
- ' Programming Language :: Python :: 3.5\n'
+ ' Programming Language :: Python :: 3.5\n',
)
with get_dist(tmpdir) as dist:
' two\n'
'classifiers =\n'
' Framework :: Django\n'
- ' Programming Language :: Python :: 3.5\n'
+ ' Programming Language :: Python :: 3.5\n',
)
with get_dist(tmpdir) as dist:
metadata = dist.metadata
'[metadata]\n'
'project_urls =\n'
' Link One = https://example.com/one/\n'
- ' Link Two = https://example.com/two/\n'
+ ' Link Two = https://example.com/two/\n',
)
with get_dist(tmpdir) as dist:
metadata = dist.metadata
def test_version(self, tmpdir):
package_dir, config = fake_env(
- tmpdir,
- '[metadata]\n'
- 'version = attr: fake_package.VERSION\n'
+ tmpdir, '[metadata]\n' 'version = attr: fake_package.VERSION\n'
)
sub_a = package_dir.mkdir('subpkg_a')
sub_b = package_dir.mkdir('subpkg_b')
sub_b.join('__init__.py').write('')
sub_b.join('mod.py').write(
- 'import third_party_module\n'
- 'VERSION = (2016, 11, 26)'
+ 'import third_party_module\n' 'VERSION = (2016, 11, 26)'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
- config.write(
- '[metadata]\n'
- 'version = attr: fake_package.get_version\n'
- )
+ config.write('[metadata]\n' 'version = attr: fake_package.get_version\n')
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '3.4.5.dev'
- config.write(
- '[metadata]\n'
- 'version = attr: fake_package.VERSION_MAJOR\n'
- )
+ config.write('[metadata]\n' 'version = attr: fake_package.VERSION_MAJOR\n')
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1'
config.write(
- '[metadata]\n'
- 'version = attr: fake_package.subpkg_a.mod.VERSION\n'
+ '[metadata]\n' 'version = attr: fake_package.subpkg_a.mod.VERSION\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '2016.11.26'
config.write(
- '[metadata]\n'
- 'version = attr: fake_package.subpkg_b.mod.VERSION\n'
+ '[metadata]\n' 'version = attr: fake_package.subpkg_b.mod.VERSION\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '2016.11.26'
def test_version_file(self, tmpdir):
_, config = fake_env(
- tmpdir,
- '[metadata]\n'
- 'version = file: fake_package/version.txt\n'
+ tmpdir, '[metadata]\n' 'version = file: fake_package/version.txt\n'
)
tmpdir.join('fake_package', 'version.txt').write('1.2.3\n')
'[options]\n'
'package_dir =\n'
' = src\n',
- package_path='src/fake_package_simple'
+ package_path='src/fake_package_simple',
)
with get_dist(tmpdir) as dist:
'[options]\n'
'package_dir =\n'
' fake_package_rename = fake_dir\n',
- package_path='fake_dir'
+ package_path='fake_dir',
)
with get_dist(tmpdir) as dist:
'[options]\n'
'package_dir =\n'
' fake_package_complex = src/fake_dir\n',
- package_path='src/fake_dir'
+ package_path='src/fake_dir',
)
with get_dist(tmpdir) as dist:
def test_unknown_meta_item(self, tmpdir):
- fake_env(
- tmpdir,
- '[metadata]\n'
- 'name = fake_name\n'
- 'unknown = some\n'
- )
+ fake_env(tmpdir, '[metadata]\n' 'name = fake_name\n' 'unknown = some\n')
with get_dist(tmpdir, parse=False) as dist:
dist.parse_config_files() # Skip unknown.
def test_usupported_section(self, tmpdir):
- fake_env(
- tmpdir,
- '[metadata.some]\n'
- 'key = val\n'
- )
+ fake_env(tmpdir, '[metadata.some]\n' 'key = val\n')
with get_dist(tmpdir, parse=False) as dist:
with pytest.raises(DistutilsOptionError):
dist.parse_config_files()
def test_classifiers(self, tmpdir):
- expected = set([
- 'Framework :: Django',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.5',
- ])
+ expected = set(
+ [
+ 'Framework :: Django',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.5',
+ ]
+ )
# From file.
- _, config = fake_env(
- tmpdir,
- '[metadata]\n'
- 'classifiers = file: classifiers\n'
- )
+ _, config = fake_env(tmpdir, '[metadata]\n' 'classifiers = file: classifiers\n')
tmpdir.join('classifiers').write(
'Framework :: Django\n'
'[metadata]\n'
'version = 10.1.1\n'
'description = Some description\n'
- 'requires = some, requirement\n'
+ 'requires = some, requirement\n',
)
with pytest.deprecated_call():
assert metadata.requires == ['some', 'requirement']
def test_interpolation(self, tmpdir):
- fake_env(
- tmpdir,
- '[metadata]\n'
- 'description = %(message)s\n'
- )
+ fake_env(tmpdir, '[metadata]\n' 'description = %(message)s\n')
with pytest.raises(configparser.InterpolationMissingOptionError):
with get_dist(tmpdir):
pass
def test_non_ascii_1(self, tmpdir):
- fake_env(
- tmpdir,
- '[metadata]\n'
- 'description = éàïôñ\n',
- encoding='utf-8'
- )
+ fake_env(tmpdir, '[metadata]\n' 'description = éàïôñ\n', encoding='utf-8')
with get_dist(tmpdir):
pass
def test_non_ascii_3(self, tmpdir):
- fake_env(
- tmpdir,
- '\n'
- '# -*- coding: invalid\n'
- )
+ fake_env(tmpdir, '\n' '# -*- coding: invalid\n')
with get_dist(tmpdir):
pass
def test_non_ascii_4(self, tmpdir):
fake_env(
tmpdir,
- '# -*- coding: utf-8\n'
- '[metadata]\n'
- 'description = éàïôñ\n',
- encoding='utf-8'
+ '# -*- coding: utf-8\n' '[metadata]\n' 'description = éàïôñ\n',
+ encoding='utf-8',
)
with get_dist(tmpdir) as dist:
assert dist.metadata.description == 'éàïôñ'
'# vim: set fileencoding=iso-8859-15 :\n'
'[metadata]\n'
'description = éàïôñ\n',
- encoding='iso-8859-15'
+ encoding='iso-8859-15',
)
with pytest.raises(UnicodeDecodeError):
with get_dist(tmpdir):
tmpdir,
'[metadata]\n'
'author-email = test@test.com\n'
- 'maintainer_email = foo@foo.com\n'
- )
- msg = ("Usage of dash-separated 'author-email' will not be supported "
- "in future versions. "
- "Please use the underscore name 'author_email' instead")
+ 'maintainer_email = foo@foo.com\n',
+ )
+ msg = (
+ "Usage of dash-separated 'author-email' will not be supported "
+ "in future versions. "
+ "Please use the underscore name 'author_email' instead"
+ )
with pytest.warns(UserWarning, match=msg):
with get_dist(tmpdir) as dist:
metadata = dist.metadata
# remove this test and the method make_option_lowercase() in setuptools.dist
# when no longer needed
fake_env(
- tmpdir,
- '[metadata]\n'
- 'Name = foo\n'
- 'description = Some description\n'
+ tmpdir, '[metadata]\n' 'Name = foo\n' 'description = Some description\n'
+ )
+ msg = (
+ "Usage of uppercase key 'Name' in 'metadata' will be deprecated in "
+ "future versions. "
+ "Please use lowercase 'name' instead"
)
- msg = ("Usage of uppercase key 'Name' in 'metadata' will be deprecated in "
- "future versions. "
- "Please use lowercase 'name' instead")
with pytest.warns(UserWarning, match=msg):
with get_dist(tmpdir) as dist:
metadata = dist.metadata
class TestOptions:
-
def test_basic(self, tmpdir):
fake_env(
tmpdir,
'[options]\n'
'zip_safe = True\n'
- 'use_2to3 = 1\n'
'include_package_data = yes\n'
'package_dir = b=c, =src\n'
'packages = pack_a, pack_b.subpack\n'
'namespace_packages = pack1, pack2\n'
- 'use_2to3_fixers = your.fixers, or.here\n'
- 'use_2to3_exclude_fixers = one.here, two.there\n'
- 'convert_2to3_doctests = src/tests/one.txt, src/two.txt\n'
'scripts = bin/one.py, bin/two.py\n'
'eager_resources = bin/one.py, bin/two.py\n'
'install_requires = docutils>=0.3; pack ==1.1, ==1.3; hey\n'
'dependency_links = http://some.com/here/1, '
'http://some.com/there/2\n'
'python_requires = >=1.0, !=2.8\n'
- 'py_modules = module1, module2\n'
+ 'py_modules = module1, module2\n',
)
with get_dist(tmpdir) as dist:
assert dist.zip_safe
- assert dist.use_2to3
assert dist.include_package_data
assert dist.package_dir == {'': 'src', 'b': 'c'}
assert dist.packages == ['pack_a', 'pack_b.subpack']
assert dist.namespace_packages == ['pack1', 'pack2']
- assert dist.use_2to3_fixers == ['your.fixers', 'or.here']
- assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there']
- assert dist.convert_2to3_doctests == ([
- 'src/tests/one.txt', 'src/two.txt'])
assert dist.scripts == ['bin/one.py', 'bin/two.py']
- assert dist.dependency_links == ([
- 'http://some.com/here/1',
- 'http://some.com/there/2'
- ])
- assert dist.install_requires == ([
- 'docutils>=0.3',
- 'pack==1.1,==1.3',
- 'hey'
- ])
- assert dist.setup_requires == ([
- 'docutils>=0.3',
- 'spack ==1.1, ==1.3',
- 'there'
- ])
+ assert dist.dependency_links == (
+ ['http://some.com/here/1', 'http://some.com/there/2']
+ )
+ assert dist.install_requires == (
+ ['docutils>=0.3', 'pack==1.1,==1.3', 'hey']
+ )
+ assert dist.setup_requires == (
+ ['docutils>=0.3', 'spack ==1.1, ==1.3', 'there']
+ )
assert dist.tests_require == ['mock==0.7.2', 'pytest']
assert dist.python_requires == '>=1.0, !=2.8'
assert dist.py_modules == ['module1', 'module2']
'namespace_packages = \n'
' pack1\n'
' pack2\n'
- 'use_2to3_fixers = \n'
- ' your.fixers\n'
- ' or.here\n'
- 'use_2to3_exclude_fixers = \n'
- ' one.here\n'
- ' two.there\n'
- 'convert_2to3_doctests = \n'
- ' src/tests/one.txt\n'
- ' src/two.txt\n'
'scripts = \n'
' bin/one.py\n'
' bin/two.py\n'
' there\n'
'dependency_links = \n'
' http://some.com/here/1\n'
- ' http://some.com/there/2\n'
+ ' http://some.com/there/2\n',
)
with get_dist(tmpdir) as dist:
assert dist.package_dir == {'': 'src', 'b': 'c'}
assert dist.packages == ['pack_a', 'pack_b.subpack']
assert dist.namespace_packages == ['pack1', 'pack2']
- assert dist.use_2to3_fixers == ['your.fixers', 'or.here']
- assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there']
- assert dist.convert_2to3_doctests == (
- ['src/tests/one.txt', 'src/two.txt'])
assert dist.scripts == ['bin/one.py', 'bin/two.py']
- assert dist.dependency_links == ([
- 'http://some.com/here/1',
- 'http://some.com/there/2'
- ])
- assert dist.install_requires == ([
- 'docutils>=0.3',
- 'pack==1.1,==1.3',
- 'hey'
- ])
- assert dist.setup_requires == ([
- 'docutils>=0.3',
- 'spack ==1.1, ==1.3',
- 'there'
- ])
+ assert dist.dependency_links == (
+ ['http://some.com/here/1', 'http://some.com/there/2']
+ )
+ assert dist.install_requires == (
+ ['docutils>=0.3', 'pack==1.1,==1.3', 'hey']
+ )
+ assert dist.setup_requires == (
+ ['docutils>=0.3', 'spack ==1.1, ==1.3', 'there']
+ )
assert dist.tests_require == ['mock==0.7.2', 'pytest']
def test_package_dir_fail(self, tmpdir):
- fake_env(
- tmpdir,
- '[options]\n'
- 'package_dir = a b\n'
- )
+ fake_env(tmpdir, '[options]\n' 'package_dir = a b\n')
with get_dist(tmpdir, parse=False) as dist:
with pytest.raises(DistutilsOptionError):
dist.parse_config_files()
'\n'
'[options.exclude_package_data]\n'
'* = fake1.txt, fake2.txt\n'
- 'hello = *.dat\n'
+ 'hello = *.dat\n',
)
with get_dist(tmpdir) as dist:
}
def test_packages(self, tmpdir):
- fake_env(
- tmpdir,
- '[options]\n'
- 'packages = find:\n'
- )
+ fake_env(tmpdir, '[options]\n' 'packages = find:\n')
with get_dist(tmpdir) as dist:
assert dist.packages == ['fake_package']
def test_find_directive(self, tmpdir):
- dir_package, config = fake_env(
- tmpdir,
- '[options]\n'
- 'packages = find:\n'
- )
+ dir_package, config = fake_env(tmpdir, '[options]\n' 'packages = find:\n')
dir_sub_one, _ = make_package_dir('sub_one', dir_package)
dir_sub_two, _ = make_package_dir('sub_two', dir_package)
with get_dist(tmpdir) as dist:
- assert set(dist.packages) == set([
- 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one'
- ])
+ assert set(dist.packages) == set(
+ ['fake_package', 'fake_package.sub_two', 'fake_package.sub_one']
+ )
config.write(
'[options]\n'
' fake_package.sub_one\n'
)
with get_dist(tmpdir) as dist:
- assert set(dist.packages) == set(
- ['fake_package', 'fake_package.sub_two'])
+ assert set(dist.packages) == set(['fake_package', 'fake_package.sub_two'])
def test_find_namespace_directive(self, tmpdir):
dir_package, config = fake_env(
- tmpdir,
- '[options]\n'
- 'packages = find_namespace:\n'
+ tmpdir, '[options]\n' 'packages = find_namespace:\n'
)
dir_sub_one, _ = make_package_dir('sub_one', dir_package)
with get_dist(tmpdir) as dist:
assert set(dist.packages) == {
- 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one'
+ 'fake_package',
+ 'fake_package.sub_two',
+ 'fake_package.sub_one',
}
config.write(
' fake_package.sub_one\n'
)
with get_dist(tmpdir) as dist:
- assert set(dist.packages) == {
- 'fake_package', 'fake_package.sub_two'
- }
+ assert set(dist.packages) == {'fake_package', 'fake_package.sub_two'}
def test_extras_require(self, tmpdir):
fake_env(
'pdf = ReportLab>=1.2; RXP\n'
'rest = \n'
' docutils>=0.3\n'
- ' pack ==1.1, ==1.3\n'
+ ' pack ==1.1, ==1.3\n',
)
with get_dist(tmpdir) as dist:
assert dist.extras_require == {
'pdf': ['ReportLab>=1.2', 'RXP'],
- 'rest': ['docutils>=0.3', 'pack==1.1,==1.3']
+ 'rest': ['docutils>=0.3', 'pack==1.1,==1.3'],
}
assert dist.metadata.provides_extras == set(['pdf', 'rest'])
def test_dash_preserved_extras_require(self, tmpdir):
- fake_env(
- tmpdir,
- '[options.extras_require]\n'
- 'foo-a = foo\n'
- 'foo_b = test\n'
- )
+ fake_env(tmpdir, '[options.extras_require]\n' 'foo-a = foo\n' 'foo_b = test\n')
with get_dist(tmpdir) as dist:
- assert dist.extras_require == {
- 'foo-a': ['foo'],
- 'foo_b': ['test']
- }
+ assert dist.extras_require == {'foo-a': ['foo'], 'foo_b': ['test']}
def test_entry_points(self, tmpdir):
_, config = fake_env(
'[options.entry_points]\n'
'group1 = point1 = pack.module:func, '
'.point2 = pack.module2:func_rest [rest]\n'
- 'group2 = point3 = pack.module:func2\n'
+ 'group2 = point3 = pack.module:func2\n',
)
with get_dist(tmpdir) as dist:
'point1 = pack.module:func',
'.point2 = pack.module2:func_rest [rest]',
],
- 'group2': ['point3 = pack.module:func2']
+ 'group2': ['point3 = pack.module:func2'],
}
expected = (
tmpdir.join('entry_points').write(expected)
# From file.
- config.write(
- '[options]\n'
- 'entry_points = file: entry_points\n'
- )
+ config.write('[options]\n' 'entry_points = file: entry_points\n')
with get_dist(tmpdir) as dist:
assert dist.entry_points == expected
'[options.entry_points]\n'
'GROUP1 = point1 = pack.module:func, '
'.point2 = pack.module2:func_rest [rest]\n'
- 'group2 = point3 = pack.module:func2\n'
+ 'group2 = point3 = pack.module:func2\n',
)
with get_dist(tmpdir) as dist:
'point1 = pack.module:func',
'.point2 = pack.module2:func_rest [rest]',
],
- 'group2': ['point3 = pack.module:func2']
+ 'group2': ['point3 = pack.module:func2'],
}
def test_data_files(self, tmpdir):
'cfg =\n'
' a/b.conf\n'
' c/d.conf\n'
- 'data = e/f.dat, g/h.dat\n'
+ 'data = e/f.dat, g/h.dat\n',
)
with get_dist(tmpdir) as dist:
def test_python_requires_simple(self, tmpdir):
fake_env(
tmpdir,
- DALS("""
+ DALS(
+ """
[options]
python_requires=>=2.7
- """),
+ """
+ ),
)
with get_dist(tmpdir) as dist:
dist.parse_config_files()
def test_python_requires_compound(self, tmpdir):
fake_env(
tmpdir,
- DALS("""
+ DALS(
+ """
[options]
python_requires=>=2.7,!=3.0.*
- """),
+ """
+ ),
)
with get_dist(tmpdir) as dist:
dist.parse_config_files()
def test_python_requires_invalid(self, tmpdir):
fake_env(
tmpdir,
- DALS("""
+ DALS(
+ """
[options]
python_requires=invalid
- """),
+ """
+ ),
)
with pytest.raises(Exception):
with get_dist(tmpdir) as dist:
fake_env(
tmpdir,
- '[options]\n'
- 'cmdclass =\n'
- ' customcmd = custom_build.CustomCmd\n'
+ '[options]\n' 'cmdclass =\n' ' customcmd = custom_build.CustomCmd\n',
)
with get_dist(tmpdir) as dist:
def _fake_distribution_init(self, dist, attrs):
saved_dist_init(dist, attrs)
# see self._DISTUTUILS_UNSUPPORTED_METADATA
- setattr(dist.metadata, 'long_description_content_type',
- 'text/something')
+ setattr(dist.metadata, 'long_description_content_type', 'text/something')
# Test overwrite setup() args
- setattr(dist.metadata, 'project_urls', {
- 'Link One': 'https://example.com/one/',
- 'Link Two': 'https://example.com/two/',
- })
+ setattr(
+ dist.metadata,
+ 'project_urls',
+ {
+ 'Link One': 'https://example.com/one/',
+ 'Link Two': 'https://example.com/two/',
+ },
+ )
return None
@patch.object(_Distribution, '__init__', autospec=True)
def test_external_setters(self, mock_parent_init, tmpdir):
mock_parent_init.side_effect = self._fake_distribution_init
- dist = Distribution(attrs={
- 'project_urls': {
- 'will_be': 'ignored'
- }
- })
+ dist = Distribution(attrs={'project_urls': {'will_be': 'ignored'}})
assert dist.metadata.long_description_content_type == 'text/something'
assert dist.metadata.project_urls == {
"""
import os
-import site
import sys
-import io
import subprocess
import platform
import pathlib
from setuptools.command.develop import develop
from setuptools.dist import Distribution
-from setuptools.tests import ack_2to3
from . import contexts
from . import namespaces
setup(name='foo',
packages=['foo'],
- use_2to3=True,
)
"""
in_virtualenv = hasattr(sys, 'real_prefix')
in_venv = hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix
- @pytest.mark.skipif(
- in_virtualenv or in_venv,
- reason="Cannot run when invoked in a virtualenv or venv")
- @ack_2to3
- def test_2to3_user_mode(self, test_env):
- settings = dict(
- name='foo',
- packages=['foo'],
- use_2to3=True,
- version='0.0',
- )
- dist = Distribution(settings)
- dist.script_name = 'setup.py'
- cmd = develop(dist)
- cmd.user = 1
- cmd.ensure_finalized()
- cmd.install_dir = site.USER_SITE
- cmd.user = 1
- with contexts.quiet():
- cmd.run()
-
- # let's see if we got our egg link at the right place
- content = os.listdir(site.USER_SITE)
- content.sort()
- assert content == ['easy-install.pth', 'foo.egg-link']
-
- # Check that we are using the right code.
- fn = os.path.join(site.USER_SITE, 'foo.egg-link')
- with io.open(fn) as egg_link_file:
- path = egg_link_file.read().split()[0].strip()
- fn = os.path.join(path, 'foo', '__init__.py')
- with io.open(fn) as init_file:
- init = init_file.read().strip()
-
- expected = 'print("foo")'
- assert init == expected
-
def test_console_scripts(self, tmpdir):
"""
Test that console scripts are installed and that they reference
"""
pytest.skip(
"TODO: needs a fixture to cause 'develop' "
- "to be invoked without mutating environment.")
+ "to be invoked without mutating environment."
+ )
settings = dict(
name='foo',
packages=['foo'],
of what _resolve_setup_path is intending to do. Come up with
more meaningful cases that look like real-world scenarios.
"""
+
def test_resolve_setup_path_cwd(self):
assert develop._resolve_setup_path('.', '.', '.') == '.'
class TestNamespaces:
-
@staticmethod
def install_develop(src_dir, target):
sys.executable,
'setup.py',
'develop',
- '--install-dir', str(target),
+ '--install-dir',
+ str(target),
]
with src_dir.as_cwd():
with test.test.paths_on_pythonpath([str(target)]):
'pip',
'install',
str(pkg_A),
- '-t', str(target),
+ '-t',
+ str(target),
]
subprocess.check_call(install_cmd)
self.install_develop(pkg_B, target)
namespaces.make_site_dir(target)
try_import = [
sys.executable,
- '-c', 'import myns.pkgA; import myns.pkgB',
+ '-c',
+ 'import myns.pkgA; import myns.pkgB',
]
with test.test.paths_on_pythonpath([str(target)]):
subprocess.check_call(try_import)
# additionally ensure that pkg_resources import works
pkg_resources_imp = [
sys.executable,
- '-c', 'import pkg_resources',
+ '-c',
+ 'import pkg_resources',
]
with test.test.paths_on_pythonpath([str(target)]):
subprocess.check_call(pkg_resources_imp)
def install_workaround(site_packages):
site_packages.mkdir(parents=True)
sc = site_packages / 'sitecustomize.py'
- sc.write_text(textwrap.dedent("""
+ sc.write_text(
+ textwrap.dedent(
+ """
import site
import pathlib
here = pathlib.Path(__file__).parent
site.addsitedir(str(here))
- """).lstrip())
+ """
+ ).lstrip()
+ )
@pytest.mark.xfail(
platform.python_implementation() == 'PyPy',
site_packages = prefix / next(
pathlib.Path(path).relative_to(sys.prefix)
for path in sys.path
- if 'site-packages' in path
- and path.startswith(sys.prefix)
+ if 'site-packages' in path and path.startswith(sys.prefix)
)
# install the workaround
env = dict(os.environ, PYTHONPATH=str(site_packages))
cmd = [
sys.executable,
- '-m', 'pip',
+ '-m',
+ 'pip',
'install',
'--editable',
str(sample_project),
- '--prefix', str(prefix),
+ '--prefix',
+ str(prefix),
'--no-build-isolation',
]
subprocess.check_call(cmd, env=env)
-import mock
from distutils import log
import os
from setuptools.command.test import test
from setuptools.dist import Distribution
-from setuptools.tests import ack_2to3
from .textwrap import DALS
-SETUP_PY = DALS("""
+SETUP_PY = DALS(
+ """
from setuptools import setup
setup(name='foo',
namespace_packages=['name'],
test_suite='name.space.tests.test_suite',
)
- """)
+ """
+)
-NS_INIT = DALS("""
+NS_INIT = DALS(
+ """
# -*- coding: Latin-1 -*-
# Söme Arbiträry Ünicode to test Distribute Issüé 310
try:
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
- """)
+ """
+)
-TEST_PY = DALS("""
+TEST_PY = DALS(
+ """
import unittest
class TestTest(unittest.TestCase):
def test_test(self):
- print "Foo" # Should fail under Python 3 unless 2to3 is used
+ print "Foo" # Should fail under Python 3
test_suite = unittest.makeSuite(TestTest)
- """)
+ """
+)
@pytest.fixture
log.set_verbosity(0)
-@pytest.mark.usefixtures('sample_test', 'quiet_log')
-@ack_2to3
-def test_test(capfd):
- params = dict(
- name='foo',
- packages=['name', 'name.space', 'name.space.tests'],
- namespace_packages=['name'],
- test_suite='name.space.tests.test_suite',
- use_2to3=True,
- )
- dist = Distribution(params)
- dist.script_name = 'setup.py'
- cmd = test(dist)
- cmd.ensure_finalized()
- cmd.run()
- out, err = capfd.readouterr()
- assert out == 'Foo\n'
-
-
@pytest.mark.usefixtures('tmpdir_cwd', 'quiet_log')
def test_tests_are_run_once(capfd):
params = dict(
with open('dummy/__init__.py', 'wt'):
pass
with open('dummy/test_dummy.py', 'wt') as f:
- f.write(DALS(
- """
+ f.write(
+ DALS(
+ """
import unittest
class TestTest(unittest.TestCase):
def test_test(self):
print('Foo')
- """))
+ """
+ )
+ )
dist = Distribution(params)
dist.script_name = 'setup.py'
cmd = test(dist)
cmd.run()
out, err = capfd.readouterr()
assert out == 'Foo\n'
-
-
-@pytest.mark.usefixtures('sample_test')
-@ack_2to3
-def test_warns_deprecation(capfd):
- params = dict(
- name='foo',
- packages=['name', 'name.space', 'name.space.tests'],
- namespace_packages=['name'],
- test_suite='name.space.tests.test_suite',
- use_2to3=True
- )
- dist = Distribution(params)
- dist.script_name = 'setup.py'
- cmd = test(dist)
- cmd.ensure_finalized()
- cmd.announce = mock.Mock()
- cmd.run()
- capfd.readouterr()
- msg = (
- "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."
- )
- cmd.announce.assert_any_call(msg, log.WARN)
-
-
-@pytest.mark.usefixtures('sample_test')
-@ack_2to3
-def test_deprecation_stderr(capfd):
- params = dict(
- name='foo',
- packages=['name', 'name.space', 'name.space.tests'],
- namespace_packages=['name'],
- test_suite='name.space.tests.test_suite',
- use_2to3=True
- )
- dist = Distribution(params)
- dist.script_name = 'setup.py'
- cmd = test(dist)
- cmd.ensure_finalized()
- cmd.run()
- out, err = capfd.readouterr()
- msg = (
- "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.\n"
- )
- assert msg in err