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

Merge branch 'master'

parents b4f2df19 c218b650
v36.6.2
v36.7.2
-------
* #701: Fixed duplicate test discovery on Python 3.
v36.7.1
-------
* #1193: Avoid test failures in bdist_egg when
PYTHONDONTWRITEBYTECODE is set.
v36.7.0
-------
* #1054: Support ``setup_requires`` in ``setup.cfg`` files.
v36.6.1
-------
* #1132: Removed redundant and costly serialization/parsing step
in ``EntryPoint.__init__``.
* #844: ``bdist_egg --exclude-source-files`` now tested and works
on Python 3.
v36.6.0
-------
......
[bumpversion]
current_version = 36.6.0
current_version = 36.7.1
commit = True
tag = True
......@@ -26,3 +26,4 @@ universal = 1
license_file = LICENSE
[bumpversion:file:setup.py]
......@@ -89,7 +89,7 @@ def pypi_link(pkg_filename):
setup_params = dict(
name="setuptools",
version="36.6.0",
version="36.7.1",
description="Easily download, build, install, upgrade, and uninstall "
"Python packages",
author="Python Packaging Authority",
......
......@@ -109,7 +109,27 @@ class PEP420PackageFinder(PackageFinder):
find_packages = PackageFinder.find
setup = distutils.core.setup
def _install_setup_requires(attrs):
# Note: do not use `setuptools.Distribution` directly, as
# our PEP 517 backend patch `distutils.core.Distribution`.
dist = distutils.core.Distribution(dict(
(k, v) for k, v in attrs.items()
if k in ('dependency_links', 'setup_requires')
))
# Honor setup.cfg's options.
dist.parse_config_files(ignore_option_errors=True)
if dist.setup_requires:
dist.fetch_build_eggs(dist.setup_requires)
def setup(**attrs):
# Make sure we have any requirements needed to interpret 'attrs'.
_install_setup_requires(attrs)
return distutils.core.setup(**attrs)
setup.__doc__ = distutils.core.setup.__doc__
_Command = monkey.get_unpatched(distutils.core.Command)
......
......@@ -2,7 +2,8 @@ __all__ = [
'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop',
'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts',
'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts',
'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib', 'dist_info',
'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib',
'dist_info',
]
from distutils.command.bdist import bdist
......
......@@ -8,6 +8,7 @@ from distutils import log
from types import CodeType
import sys
import os
import re
import textwrap
import marshal
......@@ -240,11 +241,26 @@ class bdist_egg(Command):
log.info("Removing .py files from temporary directory")
for base, dirs, files in walk_egg(self.bdist_dir):
for name in files:
path = os.path.join(base, name)
if name.endswith('.py'):
path = os.path.join(base, name)
log.debug("Deleting %s", path)
os.unlink(path)
if base.endswith('__pycache__'):
path_old = path
pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc'
m = re.match(pattern, name)
path_new = os.path.join(base, os.pardir, m.group('name') + '.pyc')
log.info("Renaming file from [%s] to [%s]" % (path_old, path_new))
try:
os.remove(path_new)
except OSError:
pass
os.rename(path_old, path_new)
def zip_safe(self):
safe = getattr(self.distribution, 'zip_safe', None)
if safe is not None:
......
......@@ -95,7 +95,9 @@ class develop(namespaces.DevelopInstaller, easy_install):
path_to_setup = egg_base.replace(os.sep, '/').rstrip('/')
if path_to_setup != os.curdir:
path_to_setup = '../' * (path_to_setup.count('/') + 1)
resolved = normalize_path(os.path.join(install_dir, egg_path, path_to_setup))
resolved = normalize_path(
os.path.join(install_dir, egg_path, path_to_setup)
)
if resolved != normalize_path(os.curdir):
raise DistutilsOptionError(
"Can't get a consistent path to setup script from"
......
......@@ -1817,7 +1817,7 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None):
# get/del patterns instead. For more detailed information see the
# following links:
# https://github.com/pypa/setuptools/issues/202#issuecomment-202913420
# https://bitbucket.org/pypy/pypy/src/dd07756a34a41f674c0cacfbc8ae1d4cc9ea2ae4/pypy/module/zipimport/interp_zipimport.py#cl-99
# http://bit.ly/2h9itJX
old_entry = cache[p]
del cache[p]
new_entry = updater and updater(p, old_entry)
......
......@@ -316,23 +316,19 @@ class Distribution(Distribution_parse_config_files, _Distribution):
have_package_data = hasattr(self, "package_data")
if not have_package_data:
self.package_data = {}
_attrs_dict = attrs or {}
if 'features' in _attrs_dict or 'require_features' in _attrs_dict:
attrs = attrs or {}
if 'features' in attrs or 'require_features' in attrs:
Feature.warn_deprecated()
self.require_features = []
self.features = {}
self.dist_files = []
self.src_root = attrs and attrs.pop("src_root", None)
self.src_root = attrs.pop("src_root", None)
self.patch_missing_pkg_info(attrs)
self.long_description_content_type = _attrs_dict.get(
self.long_description_content_type = attrs.get(
'long_description_content_type'
)
# Make sure we have any eggs needed to interpret 'attrs'
if attrs is not None:
self.dependency_links = attrs.pop('dependency_links', [])
assert_string_list(self, 'dependency_links', self.dependency_links)
if attrs and 'setup_requires' in attrs:
self.fetch_build_eggs(attrs['setup_requires'])
self.dependency_links = attrs.pop('dependency_links', [])
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, attrs)
......@@ -427,14 +423,15 @@ class Distribution(Distribution_parse_config_files, _Distribution):
req.marker = None
return req
def parse_config_files(self, filenames=None):
def parse_config_files(self, filenames=None, ignore_option_errors=False):
"""Parses configuration files from various levels
and loads configuration.
"""
_Distribution.parse_config_files(self, filenames=filenames)
parse_configuration(self, self.command_options)
parse_configuration(self, self.command_options,
ignore_option_errors=ignore_option_errors)
self._finalize_requires()
def parse_command_line(self):
......@@ -497,19 +494,20 @@ class Distribution(Distribution_parse_config_files, _Distribution):
"""Fetch an egg needed for building"""
from setuptools.command.easy_install import easy_install
dist = self.__class__({'script_args': ['easy_install']})
dist.parse_config_files()
opts = dist.get_option_dict('easy_install')
keep = (
'find_links', 'site_dirs', 'index_url', 'optimize',
'site_dirs', 'allow_hosts'
)
for key in list(opts):
if key not in keep:
del opts[key] # don't use any other settings
opts.clear()
opts.update(
(k, v)
for k, v in self.get_option_dict('easy_install').items()
if k in (
# don't use any other settings
'find_links', 'site_dirs', 'index_url',
'optimize', 'site_dirs', 'allow_hosts',
))
if self.dependency_links:
links = self.dependency_links[:]
if 'find_links' in opts:
links = opts['find_links'][1].split() + links
links = opts['find_links'][1] + links
opts['find_links'] = ('setup', links)
install_dir = self.get_egg_cache_dir()
cmd = easy_install(
......
......@@ -2,6 +2,7 @@
"""
import os
import re
import zipfile
import pytest
......@@ -16,7 +17,7 @@ setup(name='foo', py_modules=['hi'])
"""
@pytest.yield_fixture
@pytest.fixture(scope='function')
def setup_context(tmpdir):
with (tmpdir / 'setup.py').open('w') as f:
f.write(SETUP_PY)
......@@ -32,7 +33,7 @@ class Test:
script_name='setup.py',
script_args=['bdist_egg'],
name='foo',
py_modules=['hi']
py_modules=['hi'],
))
os.makedirs(os.path.join('build', 'src'))
with contexts.quiet():
......@@ -42,3 +43,24 @@ class Test:
# let's see if we got our egg link at the right place
[content] = os.listdir('dist')
assert re.match(r'foo-0.0.0-py[23].\d.egg$', content)
@pytest.mark.xfail(
os.environ.get('PYTHONDONTWRITEBYTECODE'),
reason="Byte code disabled",
)
def test_exclude_source_files(self, setup_context, user_override):
dist = Distribution(dict(
script_name='setup.py',
script_args=['bdist_egg', '--exclude-source-files'],
name='foo',
py_modules=['hi'],
))
with contexts.quiet():
dist.parse_command_line()
dist.run_commands()
[dist_name] = os.listdir('dist')
dist_filename = os.path.join('dist', dist_name)
zip = zipfile.ZipFile(dist_filename)
names = list(zi.filename for zi in zip.filelist)
assert 'hi.pyc' in names
assert 'hi.py' not in names
......@@ -39,6 +39,7 @@ def test_dist_fetch_build_egg(tmpdir):
'''.split()
with tmpdir.as_cwd():
dist = Distribution()
dist.parse_config_files()
resolved_dists = [
dist.fetch_build_egg(r)
for r in reqs
......
......@@ -381,7 +381,15 @@ class TestSetupRequires:
"""))])
yield dist_path
def test_setup_requires_overrides_version_conflict(self):
use_setup_cfg = (
(),
('dependency_links',),
('setup_requires',),
('dependency_links', 'setup_requires'),
)
@pytest.mark.parametrize('use_setup_cfg', use_setup_cfg)
def test_setup_requires_overrides_version_conflict(self, use_setup_cfg):
"""
Regression test for distribution issue 323:
https://bitbucket.org/tarek/distribute/issues/323
......@@ -397,7 +405,7 @@ class TestSetupRequires:
with contexts.save_pkg_resources_state():
with contexts.tempdir() as temp_dir:
test_pkg = create_setup_requires_package(temp_dir)
test_pkg = create_setup_requires_package(temp_dir, use_setup_cfg=use_setup_cfg)
test_setup_py = os.path.join(test_pkg, 'setup.py')
with contexts.quiet() as (stdout, stderr):
# Don't even need to install the package, just
......@@ -406,9 +414,10 @@ class TestSetupRequires:
lines = stdout.readlines()
assert len(lines) > 0
assert lines[-1].strip(), 'test_pkg'
assert lines[-1].strip() == 'test_pkg'
def test_setup_requires_override_nspkg(self):
@pytest.mark.parametrize('use_setup_cfg', use_setup_cfg)
def test_setup_requires_override_nspkg(self, use_setup_cfg):
"""
Like ``test_setup_requires_overrides_version_conflict`` but where the
``setup_requires`` package is part of a namespace package that has
......@@ -446,7 +455,8 @@ class TestSetupRequires:
""")
test_pkg = create_setup_requires_package(
temp_dir, 'foo.bar', '0.2', make_nspkg_sdist, template)
temp_dir, 'foo.bar', '0.2', make_nspkg_sdist, template,
use_setup_cfg=use_setup_cfg)
test_setup_py = os.path.join(test_pkg, 'setup.py')
......@@ -464,6 +474,38 @@ class TestSetupRequires:
assert len(lines) > 0
assert lines[-1].strip() == 'test_pkg'
@pytest.mark.parametrize('use_setup_cfg', use_setup_cfg)
def test_setup_requires_with_attr_version(self, use_setup_cfg):
def make_dependency_sdist(dist_path, distname, version):
make_sdist(dist_path, [
('setup.py',
DALS("""
import setuptools
setuptools.setup(
name={name!r},
version={version!r},
py_modules=[{name!r}],
)
""".format(name=distname, version=version))),
(distname + '.py',
DALS("""
version = 42
"""
))])
with contexts.save_pkg_resources_state():
with contexts.tempdir() as temp_dir:
test_pkg = create_setup_requires_package(
temp_dir, setup_attrs=dict(version='attr: foobar.version'),
make_package=make_dependency_sdist,
use_setup_cfg=use_setup_cfg+('version',),
)
test_setup_py = os.path.join(test_pkg, 'setup.py')
with contexts.quiet() as (stdout, stderr):
run_setup(test_setup_py, ['--version'])
lines = stdout.readlines()
assert len(lines) > 0
assert lines[-1].strip() == '42'
def make_trivial_sdist(dist_path, distname, version):
"""
......@@ -532,7 +574,8 @@ def make_sdist(dist_path, files):
def create_setup_requires_package(path, distname='foobar', version='0.1',
make_package=make_trivial_sdist,
setup_py_template=None):
setup_py_template=None, setup_attrs={},
use_setup_cfg=()):
"""Creates a source tree under path for a trivial test package that has a
single requirement in setup_requires--a tarball for that requirement is
also created and added to the dependency_links argument.
......@@ -547,11 +590,39 @@ def create_setup_requires_package(path, distname='foobar', version='0.1',
'setup_requires': ['%s==%s' % (distname, version)],
'dependency_links': [os.path.abspath(path)]
}
test_setup_attrs.update(setup_attrs)
test_pkg = os.path.join(path, 'test_pkg')
test_setup_py = os.path.join(test_pkg, 'setup.py')
os.mkdir(test_pkg)
if use_setup_cfg:
test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
options = []
metadata = []
for name in use_setup_cfg:
value = test_setup_attrs.pop(name)
if name in 'name version'.split():
section = metadata
else:
section = options
if isinstance(value, (tuple, list)):
value = ';'.join(value)
section.append('%s: %s' % (name, value))
with open(test_setup_cfg, 'w') as f:
f.write(DALS(
"""
[metadata]
{metadata}
[options]
{options}
"""
).format(
options='\n'.join(options),
metadata='\n'.join(metadata),
))
test_setup_py = os.path.join(test_pkg, 'setup.py')
if setup_py_template is None:
setup_py_template = DALS("""\
import setuptools
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment