+sudo: false
language: python
-python:
- - 2.6
- - 2.7
- - 3.3
- - 3.4
- - 3.5
- - 3.6
- - nightly
- - pypy
-matrix:
+jobs:
+ fast_finish: true
include:
- - python: 3.6
- env: LC_ALL=C LC_CTYPE=C
- - python: 2.7
- env: LC_ALL=C LC_CTYPE=C
-script:
- # need tox to get started
- - pip install tox
+ - python: 2.6
+ - python: &latest_py2 2.7
+ - python: 3.3
+ - python: 3.4
+ - python: 3.5
+ - python: &latest_py3 3.6
+ - python: nightly
+ - python: pypy
+ - python: *latest_py3
+ env: LANG=C
+ - python: *latest_py2
+ env: LANG=C
+ - stage: deploy (does actual deploy to PYPI only for tagged commits)
+ python: *latest_py3
+ install: skip
+ script: skip
+ before_deploy: python bootstrap.py
+ deploy:
+ provider: pypi
+ on:
+ tags: true
+ all_branches: true
+ user: jaraco
+ password:
+ secure: tfWrsQMH2bHrWjqnP+08IX1WlkbW94Q30f4d7lCyhWS1FIf/jBDx4jrEILNfMxQ1NCwuBRje5sihj1Ow0BFf0vVrkaeff2IdvnNDEGFduMejaEQJL3s3QrLfpiAvUbtqwyWaHfAdGfk48PovDKTx0ZTvXZKYGXZhxGCYSlG2CE6Y6RDvnEl6Tk8e+LqUohkcSOwxrRwUoyxSnUaavdGohXxDT8MJlfWOXgr2u+KsRrriZqp3l6Fdsnk4IGvy6pXpy42L1HYQyyVu9XyJilR2JTbC6eCp5f8p26093m1Qas49+t6vYb0VLqQe12dO+Jm3v4uztSS5pPQzS7PFyjEYd2Rdb6ijsdbsy1074S4q7G9Sz+T3RsPUwYEJ07lzez8cxP64dtj5j94RL8m35A1Fb1OE8hHN+4c1yLG1gudfXbem+fUhi2eqhJrzQo5vsvDv1xS5x5GIS5ZHgKHCsWcW1Tv+dsFkrhaup3uU6VkOuc9UN+7VPsGEY7NvquGpTm8O1CnGJRzuJg6nbYRGj8ORwDpI0KmrExx6akV92P72fMC/I5TCgbSQSZn370H3Jj40gz1SM30WAli9M+wFHFd4ddMVY65yxj0NLmrP+m1tvnWdKtNh/RHuoW92d9/UFtiA5IhMf1/3djfsjBq6S9NT1uaLkVkTttqrPYJ7hOql8+g=
+ distributions: release
+ skip_upload_docs: true
- # Output the env, to verify behavior
- - env
+cache: pip
- # update egg_info based on setup.py in checkout
- - python bootstrap.py
+install:
+# need tox to get started
+- pip install tox
- #- python -m tox
- - tox
+# Output the env, to verify behavior
+- env
-deploy:
- provider: pypi
- # Also update server in setup.cfg
- server: https://upload.pypi.org/legacy/
- on:
- tags: true
- all_branches: true
- python: 3.6
- condition: $LC_ALL != "C"
- user: jaraco
- password:
- secure: tfWrsQMH2bHrWjqnP+08IX1WlkbW94Q30f4d7lCyhWS1FIf/jBDx4jrEILNfMxQ1NCwuBRje5sihj1Ow0BFf0vVrkaeff2IdvnNDEGFduMejaEQJL3s3QrLfpiAvUbtqwyWaHfAdGfk48PovDKTx0ZTvXZKYGXZhxGCYSlG2CE6Y6RDvnEl6Tk8e+LqUohkcSOwxrRwUoyxSnUaavdGohXxDT8MJlfWOXgr2u+KsRrriZqp3l6Fdsnk4IGvy6pXpy42L1HYQyyVu9XyJilR2JTbC6eCp5f8p26093m1Qas49+t6vYb0VLqQe12dO+Jm3v4uztSS5pPQzS7PFyjEYd2Rdb6ijsdbsy1074S4q7G9Sz+T3RsPUwYEJ07lzez8cxP64dtj5j94RL8m35A1Fb1OE8hHN+4c1yLG1gudfXbem+fUhi2eqhJrzQo5vsvDv1xS5x5GIS5ZHgKHCsWcW1Tv+dsFkrhaup3uU6VkOuc9UN+7VPsGEY7NvquGpTm8O1CnGJRzuJg6nbYRGj8ORwDpI0KmrExx6akV92P72fMC/I5TCgbSQSZn370H3Jj40gz1SM30WAli9M+wFHFd4ddMVY65yxj0NLmrP+m1tvnWdKtNh/RHuoW92d9/UFtiA5IhMf1/3djfsjBq6S9NT1uaLkVkTttqrPYJ7hOql8+g=
- distributions: release
- skip_upload_docs: true
+# update egg_info based on setup.py in checkout
+- python bootstrap.py
+
+# Check that setuptools can be installed in a clean environment
+- tests/clean_install.sh
+
+script: tox
+v36.2.0
+-------
+
+* #1081: Environment markers indicated in ``install_requires``
+ are now processed and treated as nameless ``extras_require``
+ with markers, allowing their metadata in requires.txt to be
+ correctly generated.
+
+* #1053: Tagged commits are now released using Travis-CI
+ build stages, meaning releases depend on passing tests on
+ all supported Python versions (Linux) and not just the latest
+ Python version.
+
v36.1.1
-------
* #992: In msvc.msvc9_query_vcvarsall, ensure the
returned dicts have str values and not Unicode for
- compatibilty with os.environ.
+ compatibility with os.environ.
v34.4.0
-------
[pytest]
-addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/test_pypi.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt --ignore scripts/upload-old-releases-as-zip.py --ignore pavement.py --ignore setuptools/tests/mod_with_constant.py
+addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/test_pypi.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt --ignore scripts/upload-old-releases-as-zip.py --ignore pavement.py --ignore setuptools/tests/mod_with_constant.py -rsxX
norecursedirs=dist build *.egg setuptools/extern pkg_resources/extern .*
flake8-ignore =
setuptools/site-patch.py F821
[bumpversion]
-current_version = 36.1.1
+current_version = 36.2.0
commit = True
tag = True
setup_params = dict(
name="setuptools",
- version="36.1.1",
+ version="36.2.0",
description="Easily download, build, install, upgrade, and uninstall "
"Python packages",
author="Python Packaging Authority",
import distutils.core
import distutils.cmd
import distutils.dist
-from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
- DistutilsSetupError)
+import itertools
+import operator
+from collections import defaultdict
+from distutils.errors import (
+ DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
+)
from distutils.util import rfc822_escape
from setuptools.extern import six
-from setuptools.extern.six.moves import map
+from setuptools.extern.six.moves import map, filter
from pkg_resources.extern import packaging
-__import__('pkg_resources.extern.packaging.specifiers')
-__import__('pkg_resources.extern.packaging.version')
-
from setuptools.depends import Require
from setuptools import windows_support
from setuptools.monkey import get_unpatched
import pkg_resources
from .py36compat import Distribution_parse_config_files
+__import__('pkg_resources.extern.packaging.specifiers')
+__import__('pkg_resources.extern.packaging.version')
+
def _get_unpatched(cls):
warnings.warn("Do not call this function", DeprecationWarning)
def check_extras(dist, attr, value):
"""Verify that extras_require mapping is valid"""
try:
- for k, v in value.items():
- if ':' in k:
- k, m = k.split(':', 1)
- if pkg_resources.invalid_marker(m):
- raise DistutilsSetupError("Invalid environment marker: " + m)
- list(pkg_resources.parse_requirements(v))
+ list(itertools.starmap(_check_extra, value.items()))
except (TypeError, ValueError, AttributeError):
raise DistutilsSetupError(
"'extras_require' must be a dictionary whose values are "
)
+def _check_extra(extra, reqs):
+ name, sep, marker = extra.partition(':')
+ if marker and pkg_resources.invalid_marker(marker):
+ raise DistutilsSetupError("Invalid environment marker: " + marker)
+
+ # extras requirements cannot themselves have markers
+ parsed = pkg_resources.parse_requirements(reqs)
+ marked_reqs = filter(operator.attrgetter('marker'), parsed)
+ bad_req = next(marked_reqs, None)
+ if bad_req:
+ tmpl = (
+ "'extras_require' requirements cannot include "
+ "environment markers, in {name!r}: '{bad_req!s}'"
+ )
+ raise DistutilsSetupError(tmpl.format(**locals()))
+
+
def assert_bool(dist, attr, value):
"""Verify that value is True, False, 0, or 1"""
if bool(value) != value:
)
if getattr(self, 'python_requires', None):
self.metadata.python_requires = self.python_requires
+ self._finalize_requires()
+
+ def _finalize_requires(self):
+ """
+ Move requirements in `install_requires` that
+ are using environment markers to `extras_require`.
+ """
+ if not self.install_requires:
+ return
+ extras_require = defaultdict(list, (
+ (k, list(pkg_resources.parse_requirements(v)))
+ for k, v in (self.extras_require or {}).items()
+ ))
+ install_requires = []
+ for r in pkg_resources.parse_requirements(self.install_requires):
+ marker = r.marker
+ if not marker:
+ install_requires.append(r)
+ continue
+ r.marker = None
+ extras_require[':' + str(marker)].append(r)
+ self.extras_require = dict(
+ (k, [str(r) for r in v])
+ for k, v in extras_require.items()
+ )
+ self.install_requires = [str(r) for r in install_requires]
def parse_config_files(self, filenames=None):
"""Parses configuration files from various levels
ep.load()(self, ep.name, value)
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]
+ self.convert_2to3_doctests = [
+ os.path.abspath(p)
+ for p in self.convert_2to3_doctests
+ ]
else:
self.convert_2to3_doctests = []
opts['find_links'] = ('setup', links)
install_dir = self.get_egg_cache_dir()
cmd = easy_install(
- dist, args=["x"], install_dir=install_dir, exclude_scripts=True,
+ dist, args=["x"], install_dir=install_dir,
+ exclude_scripts=True,
always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True, no_report=True, user=False
)
if not feature.include_by_default():
excdef, incdef = incdef, excdef
- go.append(('with-' + name, None, 'include ' + descr + incdef))
- go.append(('without-' + name, None, 'exclude ' + descr + excdef))
+ new = (
+ ('with-' + name, None, 'include ' + descr + incdef),
+ ('without-' + name, None, 'exclude ' + descr + excdef),
+ )
+ go.extend(new)
no['without-' + name] = 'with-' + name
self.global_options = self.feature_options = go + self.global_options
if command in self.cmdclass:
return self.cmdclass[command]
- for ep in pkg_resources.iter_entry_points('distutils.commands', command):
+ eps = pkg_resources.iter_entry_points('distutils.commands', command)
+ for ep in eps:
ep.require(installer=self.fetch_build_egg)
self.cmdclass[command] = cmdclass = ep.load()
return cmdclass
name + ": this setting cannot be changed via include/exclude"
)
else:
- setattr(self, name, old + [item for item in value if item not in old])
+ new = [item for item in value if item not in old]
+ setattr(self, name, old + new)
def exclude(self, **attrs):
"""Remove items from distribution that are named in keyword arguments
@staticmethod
def warn_deprecated():
- warnings.warn(
+ msg = (
"Features are deprecated and will be removed in a future "
- "version. See https://github.com/pypa/setuptools/issues/65.",
- DeprecationWarning,
- stacklevel=3,
+ "version. See https://github.com/pypa/setuptools/issues/65."
)
+ warnings.warn(msg, DeprecationWarning, stacklevel=3)
- def __init__(self, description, standard=False, available=True,
+ def __init__(
+ self, description, standard=False, available=True,
optional=True, require_features=(), remove=(), **extras):
self.warn_deprecated()
if not remove and not require_features and not extras:
raise DistutilsSetupError(
- "Feature %s: must define 'require_features', 'remove', or at least one"
- " of 'packages', 'py_modules', etc."
+ "Feature %s: must define 'require_features', 'remove', or "
+ "at least one of 'packages', 'py_modules', etc."
)
def include_by_default(self):
"""Tests for the 'setuptools' package"""
+import locale
import sys
import os
import distutils.core
from setuptools import Feature
from setuptools.depends import Require
-c_type = os.environ.get("LC_CTYPE", os.environ.get("LC_ALL"))
-is_ascii = c_type in ("C", "POSIX")
+is_ascii = locale.getpreferredencoding() == 'ANSI_X3.4-1968'
fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale")
from pkg_resources import normalize_path, working_set
from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server
+from setuptools.tests import fail_on_ascii
import pkg_resources
from .py26compat import tarfile_open
sdist_zip.close()
return str(sdist)
+ @fail_on_ascii
def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch):
"""
The install command should execute correctly even if
yield env
dict_order_fails = pytest.mark.skipif(
- sys.version_info < (2,7),
+ sys.version_info < (2, 7),
reason="Intermittent failures on Python 2.6",
)
'setup.py': setup_script,
})
+ mismatch_marker = "python_version<'{this_ver}'".format(
+ this_ver=sys.version_info[0],
+ )
+
def test_install_requires_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """install_requires=["barbazquux;python_version<'2'"],""")
+ tmpl = 'install_requires=["barbazquux;{marker}"],'
+ req = tmpl.format(marker=self.mismatch_marker)
+ self._setup_script_with_requires(req)
self._run_install_command(tmpdir_cwd, env)
egg_info_dir = self._find_egg_info_files(env.paths['lib']).base
requires_txt = os.path.join(egg_info_dir, 'requires.txt')
- assert "barbazquux;python_version<'2'" in open(
- requires_txt).read().split('\n')
+ with open(requires_txt) as fp:
+ install_requires = fp.read()
+ expected_requires = DALS('''
+ [:python_version < "{sys.version_info[0]}"]
+ barbazquux
+ ''').format(sys=sys)
+ assert install_requires.lstrip() == expected_requires
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
def test_setup_requires_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """setup_requires=["barbazquux;python_version<'2'"],""")
+ tmpl = 'setup_requires=["barbazquux;{marker}"],'
+ req = tmpl.format(marker=self.mismatch_marker)
+ self._setup_script_with_requires(req)
self._run_install_command(tmpdir_cwd, env)
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
def test_tests_require_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """tests_require=["barbazquux;python_version<'2'"],""")
+ tmpl = 'tests_require=["barbazquux;{marker}"],'
+ req = tmpl.format(marker=self.mismatch_marker)
+ self._setup_script_with_requires(req)
self._run_install_command(
tmpdir_cwd, env, cmd=['test'], output="Ran 0 tests in")
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
- def test_extra_requires_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """extra_requires={":python_version<'2'": ["barbazquux"]},""")
+ def test_extras_require_with_markers(self, tmpdir_cwd, env):
+ tmpl = 'extras_require={{":{marker}": ["barbazquux"]}},'
+ req = tmpl.format(marker=self.mismatch_marker)
+ self._setup_script_with_requires(req)
self._run_install_command(tmpdir_cwd, env)
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
+ def test_extras_require_with_markers_in_req(self, tmpdir_cwd, env):
+ tmpl = 'extras_require={{"extra": ["barbazquux; {marker}"]}},'
+ req = tmpl.format(marker=self.mismatch_marker)
+ self._setup_script_with_requires(req)
+ with pytest.raises(AssertionError):
+ self._run_install_command(tmpdir_cwd, env)
+
def test_python_requires_egg_info(self, tmpdir_cwd, env):
self._setup_script_with_requires(
"""python_requires='>=2.7.12',""")
--- /dev/null
+#!/usr/bin/env bash
+
+# This test was created in
+# https://github.com/pypa/setuptools/pull/1050
+# but it really should be incorporated into the test suite
+# such that it runs on Windows and doesn't depend on
+# virtualenv. Moving to test_integration will likely address
+# those concerns.
+
+set -o errexit
+set -o xtrace
+
+# Create a temporary directory to install the virtualenv in
+VENV_DIR="$(mktemp -d)"
+function cleanup() {
+ rm -rf "$VENV_DIR"
+}
+trap cleanup EXIT
+
+# Create a virtualenv that doesn't have pip or setuptools installed
+wget https://raw.githubusercontent.com/pypa/virtualenv/master/virtualenv.py
+python virtualenv.py --no-wheel --no-pip --no-setuptools "$VENV_DIR"
+source "$VENV_DIR/bin/activate"
+
+# Now try to install setuptools
+python bootstrap.py
+python setup.py install
[testenv]
deps=-rtests/requirements.txt
passenv=APPDATA USERPROFILE HOMEDRIVE HOMEPATH windir APPVEYOR
-commands=py.test {posargs:-rsx}
+commands=py.test {posargs}
usedevelop=True