aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/tests
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/tests')
-rw-r--r--setuptools/tests/__init__.py2
-rw-r--r--setuptools/tests/environment.py2
-rw-r--r--setuptools/tests/files.py9
-rw-r--r--setuptools/tests/requirements.txt12
-rw-r--r--setuptools/tests/server.py33
-rw-r--r--setuptools/tests/test_bdist_egg.py17
-rw-r--r--setuptools/tests/test_build_clib.py12
-rw-r--r--setuptools/tests/test_build_ext.py70
-rw-r--r--setuptools/tests/test_build_meta.py429
-rw-r--r--setuptools/tests/test_build_py.py10
-rw-r--r--setuptools/tests/test_config.py141
-rw-r--r--setuptools/tests/test_depends.py18
-rw-r--r--setuptools/tests/test_develop.py4
-rw-r--r--setuptools/tests/test_dist.py199
-rw-r--r--setuptools/tests/test_easy_install.py316
-rw-r--r--setuptools/tests/test_egg_info.py340
-rw-r--r--setuptools/tests/test_extern.py22
-rw-r--r--setuptools/tests/test_find_packages.py11
-rw-r--r--setuptools/tests/test_glibc.py52
-rw-r--r--setuptools/tests/test_install_scripts.py6
-rw-r--r--setuptools/tests/test_integration.py31
-rw-r--r--setuptools/tests/test_manifest.py133
-rw-r--r--setuptools/tests/test_msvc.py5
-rw-r--r--setuptools/tests/test_msvc14.py84
-rw-r--r--setuptools/tests/test_namespaces.py1
-rw-r--r--setuptools/tests/test_packageindex.py74
-rw-r--r--setuptools/tests/test_pep425tags.py168
-rw-r--r--setuptools/tests/test_register.py43
-rw-r--r--setuptools/tests/test_sandbox.py3
-rw-r--r--setuptools/tests/test_sdist.py122
-rw-r--r--setuptools/tests/test_setopt.py36
-rw-r--r--setuptools/tests/test_setuptools.py89
-rw-r--r--setuptools/tests/test_test.py63
-rw-r--r--setuptools/tests/test_upload.py212
-rw-r--r--setuptools/tests/test_virtualenv.py83
-rw-r--r--setuptools/tests/test_wheel.py52
-rw-r--r--setuptools/tests/test_windows_wrappers.py13
37 files changed, 1960 insertions, 957 deletions
diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py
index 5f4a1c29..9c77b51f 100644
--- a/setuptools/tests/__init__.py
+++ b/setuptools/tests/__init__.py
@@ -6,7 +6,7 @@ from setuptools.extern.six import PY2, PY3
__all__ = [
- 'fail_on_ascii', 'py2_only', 'py3_only'
+ 'fail_on_ascii', 'py2_only', 'py3_only'
]
diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py
index c67898ca..bd3119ef 100644
--- a/setuptools/tests/environment.py
+++ b/setuptools/tests/environment.py
@@ -46,6 +46,8 @@ def run_setup_py(cmd, pypath=None, path=None,
cmd, stdout=_PIPE, stderr=_PIPE, shell=shell, env=env,
)
+ if isinstance(data_stream, tuple):
+ data_stream = slice(*data_stream)
data = proc.communicate()[data_stream]
except OSError:
return 1, ''
diff --git a/setuptools/tests/files.py b/setuptools/tests/files.py
index 465a6b41..bad2189d 100644
--- a/setuptools/tests/files.py
+++ b/setuptools/tests/files.py
@@ -6,10 +6,13 @@ import pkg_resources.py31compat
def build_files(file_defs, prefix=""):
"""
- Build a set of files/directories, as described by the file_defs dictionary.
+ Build a set of files/directories, as described by the
+ file_defs dictionary.
- Each key/value pair in the dictionary is interpreted as a filename/contents
- pair. If the contents value is a dictionary, a directory is created, and the
+ Each key/value pair in the dictionary is interpreted as
+ a filename/contents
+ pair. If the contents value is a dictionary, a directory
+ is created, and the
dictionary interpreted as the files within it, recursively.
For example:
diff --git a/setuptools/tests/requirements.txt b/setuptools/tests/requirements.txt
new file mode 100644
index 00000000..19bf5aef
--- /dev/null
+++ b/setuptools/tests/requirements.txt
@@ -0,0 +1,12 @@
+mock
+pytest-flake8
+flake8-2020; python_version>="3.6"
+virtualenv>=13.0.0
+pytest-virtualenv>=1.2.7
+pytest>=3.7
+wheel
+coverage>=4.5.1
+pytest-cov>=2.5.1
+paver; python_version>="3.6"
+futures; python_version=="2.7"
+pip>=19.1 # For proper file:// URLs support.
diff --git a/setuptools/tests/server.py b/setuptools/tests/server.py
index 35312120..8b17b081 100644
--- a/setuptools/tests/server.py
+++ b/setuptools/tests/server.py
@@ -1,10 +1,13 @@
"""Basic http server for tests to simulate PyPI or custom indexes
"""
+import os
import time
import threading
from setuptools.extern.six.moves import BaseHTTPServer, SimpleHTTPServer
+from setuptools.extern.six.moves.urllib_parse import urljoin
+from setuptools.extern.six.moves.urllib.request import pathname2url
class IndexServer(BaseHTTPServer.HTTPServer):
@@ -19,10 +22,11 @@ class IndexServer(BaseHTTPServer.HTTPServer):
s.stop()
"""
- def __init__(self, server_address=('', 0),
+ def __init__(
+ self, server_address=('', 0),
RequestHandlerClass=SimpleHTTPServer.SimpleHTTPRequestHandler):
- BaseHTTPServer.HTTPServer.__init__(self, server_address,
- RequestHandlerClass)
+ BaseHTTPServer.HTTPServer.__init__(
+ self, server_address, RequestHandlerClass)
self._run = True
def start(self):
@@ -56,10 +60,11 @@ class MockServer(BaseHTTPServer.HTTPServer, threading.Thread):
A simple HTTP Server that records the requests made to it.
"""
- def __init__(self, server_address=('', 0),
+ def __init__(
+ self, server_address=('', 0),
RequestHandlerClass=RequestRecorder):
- BaseHTTPServer.HTTPServer.__init__(self, server_address,
- RequestHandlerClass)
+ BaseHTTPServer.HTTPServer.__init__(
+ self, server_address, RequestHandlerClass)
threading.Thread.__init__(self)
self.setDaemon(True)
self.requests = []
@@ -68,5 +73,19 @@ class MockServer(BaseHTTPServer.HTTPServer, threading.Thread):
self.serve_forever()
@property
+ def netloc(self):
+ return 'localhost:%s' % self.server_port
+
+ @property
def url(self):
- return 'http://localhost:%(server_port)s/' % vars(self)
+ return 'http://%s/' % self.netloc
+
+
+def path_to_url(path, authority=None):
+ """ Convert a path to a file: URL. """
+ path = os.path.normpath(os.path.abspath(path))
+ base = 'file:'
+ if authority is not None:
+ base += '//' + authority
+ url = urljoin(base, pathname2url(path))
+ return url
diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py
index 54742aa6..8760ea30 100644
--- a/setuptools/tests/test_bdist_egg.py
+++ b/setuptools/tests/test_bdist_egg.py
@@ -7,6 +7,7 @@ import zipfile
import pytest
from setuptools.dist import Distribution
+from setuptools import SetuptoolsDeprecationWarning
from . import contexts
@@ -42,7 +43,7 @@ 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)
+ assert re.match(r'foo-0.0.0-py[23].\d+.egg$', content)
@pytest.mark.xfail(
os.environ.get('PYTHONDONTWRITEBYTECODE'),
@@ -64,3 +65,17 @@ class Test:
names = list(zi.filename for zi in zip.filelist)
assert 'hi.pyc' in names
assert 'hi.py' not in names
+
+ def test_eggsecutable_warning(self, setup_context, user_override):
+ dist = Distribution(dict(
+ script_name='setup.py',
+ script_args=['bdist_egg'],
+ name='foo',
+ py_modules=['hi'],
+ entry_points={
+ 'setuptools.installation':
+ ['eggsecutable = my_package.some_module:main_func']},
+ ))
+ dist.parse_command_line()
+ with pytest.warns(SetuptoolsDeprecationWarning):
+ dist.run_commands()
diff --git a/setuptools/tests/test_build_clib.py b/setuptools/tests/test_build_clib.py
index aebcc350..48bea2b4 100644
--- a/setuptools/tests/test_build_clib.py
+++ b/setuptools/tests/test_build_clib.py
@@ -1,6 +1,4 @@
import pytest
-import os
-import shutil
import mock
from distutils.errors import DistutilsSetupError
@@ -10,8 +8,7 @@ from setuptools.dist import Distribution
class TestBuildCLib:
@mock.patch(
- 'setuptools.command.build_clib.newer_pairwise_group'
- )
+ 'setuptools.command.build_clib.newer_pairwise_group')
def test_build_libraries(self, mock_newer):
dist = Distribution()
cmd = build_clib(dist)
@@ -40,13 +37,14 @@ class TestBuildCLib:
# with that out of the way, let's see if the crude dependency
# system works
cmd.compiler = mock.MagicMock(spec=cmd.compiler)
- mock_newer.return_value = ([],[])
+ mock_newer.return_value = ([], [])
obj_deps = {'': ('global.h',), 'example.c': ('example.h',)}
- libs = [('example', {'sources': ['example.c'] ,'obj_deps': obj_deps})]
+ libs = [('example', {'sources': ['example.c'], 'obj_deps': obj_deps})]
cmd.build_libraries(libs)
- assert [['example.c', 'global.h', 'example.h']] in mock_newer.call_args[0]
+ assert [['example.c', 'global.h', 'example.h']] in \
+ mock_newer.call_args[0]
assert not cmd.compiler.compile.called
assert cmd.compiler.create_static_lib.call_count == 1
diff --git a/setuptools/tests/test_build_ext.py b/setuptools/tests/test_build_ext.py
index 60257154..3dc87ca3 100644
--- a/setuptools/tests/test_build_ext.py
+++ b/setuptools/tests/test_build_ext.py
@@ -8,6 +8,10 @@ from setuptools.command.build_ext import build_ext, get_abi3_suffix
from setuptools.dist import Distribution
from setuptools.extension import Extension
+from . import environment
+from .files import build_files
+from .textwrap import DALS
+
class TestBuildExt:
def test_get_ext_filename(self):
@@ -43,3 +47,69 @@ class TestBuildExt:
assert res.endswith('eggs.pyd')
else:
assert 'abi3' in res
+
+
+def test_build_ext_config_handling(tmpdir_cwd):
+ files = {
+ 'setup.py': DALS(
+ """
+ from setuptools import Extension, setup
+ setup(
+ name='foo',
+ version='0.0.0',
+ ext_modules=[Extension('foo', ['foo.c'])],
+ )
+ """),
+ 'foo.c': DALS(
+ """
+ #include "Python.h"
+
+ #if PY_MAJOR_VERSION >= 3
+
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "foo",
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ #define INITERROR return NULL
+
+ PyMODINIT_FUNC PyInit_foo(void)
+
+ #else
+
+ #define INITERROR return
+
+ void initfoo(void)
+
+ #endif
+ {
+ #if PY_MAJOR_VERSION >= 3
+ PyObject *module = PyModule_Create(&moduledef);
+ #else
+ PyObject *module = Py_InitModule("extension", NULL);
+ #endif
+ if (module == NULL)
+ INITERROR;
+ #if PY_MAJOR_VERSION >= 3
+ return module;
+ #endif
+ }
+ """),
+ 'setup.cfg': DALS(
+ """
+ [build]
+ build-base = foo_build
+ """),
+ }
+ build_files(files)
+ code, output = environment.run_setup_py(
+ cmd=['build'], data_stream=(0, 2),
+ )
+ assert code == 0, '\nSTDOUT:\n%s\nSTDERR:\n%s' % output
diff --git a/setuptools/tests/test_build_meta.py b/setuptools/tests/test_build_meta.py
index 2a079446..8fcf3055 100644
--- a/setuptools/tests/test_build_meta.py
+++ b/setuptools/tests/test_build_meta.py
@@ -6,7 +6,6 @@ import tarfile
import pytest
-from setuptools.build_meta import build_sdist
from .files import build_files
from .textwrap import DALS
from . import py2_only
@@ -30,7 +29,7 @@ class BuildBackend(BuildBackendBase):
def __init__(self, *args, **kwargs):
super(BuildBackend, self).__init__(*args, **kwargs)
- self.pool = futures.ProcessPoolExecutor()
+ self.pool = futures.ProcessPoolExecutor(max_workers=1)
def __getattr__(self, name):
"""Handles aribrary function invocations on the build backend."""
@@ -44,12 +43,24 @@ class BuildBackend(BuildBackendBase):
class BuildBackendCaller(BuildBackendBase):
+ def __init__(self, *args, **kwargs):
+ super(BuildBackendCaller, self).__init__(*args, **kwargs)
+
+ (self.backend_name, _,
+ self.backend_obj) = self.backend_name.partition(':')
+
def __call__(self, name, *args, **kw):
"""Handles aribrary function invocations on the build backend."""
os.chdir(self.cwd)
os.environ.update(self.env)
mod = importlib.import_module(self.backend_name)
- return getattr(mod, name)(*args, **kw)
+
+ if self.backend_obj:
+ backend = getattr(mod, self.backend_obj)
+ else:
+ backend = mod
+
+ return getattr(backend, name)(*args, **kw)
defns = [
@@ -100,118 +111,338 @@ defns = [
print('hello')
"""),
},
+ {
+ 'setup.cfg': DALS("""
+ [metadata]
+ name = foo
+ version='0.0.0'
+
+ [options]
+ py_modules=hello
+ setup_requires=six
+ """),
+ 'hello.py': DALS("""
+ def run():
+ print('hello')
+ """)
+ },
]
-@pytest.fixture(params=defns)
-def build_backend(tmpdir, request):
- build_files(request.param, prefix=str(tmpdir))
- with tmpdir.as_cwd():
- yield BuildBackend(cwd='.')
-
-
-def test_get_requires_for_build_wheel(build_backend):
- actual = build_backend.get_requires_for_build_wheel()
- expected = ['six', 'wheel']
- assert sorted(actual) == sorted(expected)
-
-
-def test_get_requires_for_build_sdist(build_backend):
- actual = build_backend.get_requires_for_build_sdist()
- expected = ['six']
- assert sorted(actual) == sorted(expected)
-
-
-def test_build_wheel(build_backend):
- dist_dir = os.path.abspath('pip-wheel')
- os.makedirs(dist_dir)
- wheel_name = build_backend.build_wheel(dist_dir)
-
- assert os.path.isfile(os.path.join(dist_dir, wheel_name))
-
-
-def test_build_sdist(build_backend):
- dist_dir = os.path.abspath('pip-sdist')
- os.makedirs(dist_dir)
- sdist_name = build_backend.build_sdist(dist_dir)
-
- assert os.path.isfile(os.path.join(dist_dir, sdist_name))
-
-
-def test_prepare_metadata_for_build_wheel(build_backend):
- dist_dir = os.path.abspath('pip-dist-info')
- os.makedirs(dist_dir)
-
- dist_info = build_backend.prepare_metadata_for_build_wheel(dist_dir)
-
- assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA'))
-
-
-@py2_only
-def test_prepare_metadata_for_build_wheel_with_str(build_backend):
- dist_dir = os.path.abspath(str('pip-dist-info'))
- os.makedirs(dist_dir)
+class TestBuildMetaBackend:
+ backend_name = 'setuptools.build_meta'
+
+ def get_build_backend(self):
+ return BuildBackend(cwd='.', backend_name=self.backend_name)
+
+ @pytest.fixture(params=defns)
+ def build_backend(self, tmpdir, request):
+ build_files(request.param, prefix=str(tmpdir))
+ with tmpdir.as_cwd():
+ yield self.get_build_backend()
+
+ def test_get_requires_for_build_wheel(self, build_backend):
+ actual = build_backend.get_requires_for_build_wheel()
+ expected = ['six', 'wheel']
+ assert sorted(actual) == sorted(expected)
+
+ def test_get_requires_for_build_sdist(self, build_backend):
+ actual = build_backend.get_requires_for_build_sdist()
+ expected = ['six']
+ assert sorted(actual) == sorted(expected)
+
+ def test_build_wheel(self, build_backend):
+ dist_dir = os.path.abspath('pip-wheel')
+ os.makedirs(dist_dir)
+ wheel_name = build_backend.build_wheel(dist_dir)
+
+ assert os.path.isfile(os.path.join(dist_dir, wheel_name))
+
+ @pytest.mark.parametrize('build_type', ('wheel', 'sdist'))
+ def test_build_with_existing_file_present(self, build_type, tmpdir_cwd):
+ # Building a sdist/wheel should still succeed if there's
+ # already a sdist/wheel in the destination directory.
+ files = {
+ 'setup.py': "from setuptools import setup\nsetup()",
+ 'VERSION': "0.0.1",
+ 'setup.cfg': DALS("""
+ [metadata]
+ name = foo
+ version = file: VERSION
+ """),
+ 'pyproject.toml': DALS("""
+ [build-system]
+ requires = ["setuptools", "wheel"]
+ build-backend = "setuptools.build_meta
+ """),
+ }
+
+ build_files(files)
+
+ dist_dir = os.path.abspath('preexisting-' + build_type)
+
+ build_backend = self.get_build_backend()
+ build_method = getattr(build_backend, 'build_' + build_type)
+
+ # Build a first sdist/wheel.
+ # Note: this also check the destination directory is
+ # successfully created if it does not exist already.
+ first_result = build_method(dist_dir)
+
+ # Change version.
+ with open("VERSION", "wt") as version_file:
+ version_file.write("0.0.2")
+
+ # Build a *second* sdist/wheel.
+ second_result = build_method(dist_dir)
+
+ assert os.path.isfile(os.path.join(dist_dir, first_result))
+ assert first_result != second_result
+
+ # And if rebuilding the exact same sdist/wheel?
+ open(os.path.join(dist_dir, second_result), 'w').close()
+ third_result = build_method(dist_dir)
+ assert third_result == second_result
+ assert os.path.getsize(os.path.join(dist_dir, third_result)) > 0
+
+ def test_build_sdist(self, build_backend):
+ dist_dir = os.path.abspath('pip-sdist')
+ os.makedirs(dist_dir)
+ sdist_name = build_backend.build_sdist(dist_dir)
+
+ assert os.path.isfile(os.path.join(dist_dir, sdist_name))
+
+ def test_prepare_metadata_for_build_wheel(self, build_backend):
+ dist_dir = os.path.abspath('pip-dist-info')
+ os.makedirs(dist_dir)
+
+ dist_info = build_backend.prepare_metadata_for_build_wheel(dist_dir)
+
+ assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA'))
+
+ @py2_only
+ def test_prepare_metadata_for_build_wheel_with_str(self, build_backend):
+ dist_dir = os.path.abspath(str('pip-dist-info'))
+ os.makedirs(dist_dir)
+
+ dist_info = build_backend.prepare_metadata_for_build_wheel(dist_dir)
+
+ assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA'))
+
+ def test_build_sdist_explicit_dist(self, build_backend):
+ # explicitly specifying the dist folder should work
+ # the folder sdist_directory and the ``--dist-dir`` can be the same
+ dist_dir = os.path.abspath('dist')
+ sdist_name = build_backend.build_sdist(dist_dir)
+ assert os.path.isfile(os.path.join(dist_dir, sdist_name))
+
+ def test_build_sdist_version_change(self, build_backend):
+ sdist_into_directory = os.path.abspath("out_sdist")
+ os.makedirs(sdist_into_directory)
+
+ sdist_name = build_backend.build_sdist(sdist_into_directory)
+ assert os.path.isfile(os.path.join(sdist_into_directory, sdist_name))
+
+ # if the setup.py changes subsequent call of the build meta
+ # should still succeed, given the
+ # sdist_directory the frontend specifies is empty
+ setup_loc = os.path.abspath("setup.py")
+ if not os.path.exists(setup_loc):
+ setup_loc = os.path.abspath("setup.cfg")
+
+ with open(setup_loc, 'rt') as file_handler:
+ content = file_handler.read()
+ with open(setup_loc, 'wt') as file_handler:
+ file_handler.write(
+ content.replace("version='0.0.0'", "version='0.0.1'"))
+
+ shutil.rmtree(sdist_into_directory)
+ os.makedirs(sdist_into_directory)
+
+ sdist_name = build_backend.build_sdist("out_sdist")
+ assert os.path.isfile(
+ os.path.join(os.path.abspath("out_sdist"), sdist_name))
+
+ def test_build_sdist_pyproject_toml_exists(self, tmpdir_cwd):
+ files = {
+ 'setup.py': DALS("""
+ __import__('setuptools').setup(
+ name='foo',
+ version='0.0.0',
+ py_modules=['hello']
+ )"""),
+ 'hello.py': '',
+ 'pyproject.toml': DALS("""
+ [build-system]
+ requires = ["setuptools", "wheel"]
+ build-backend = "setuptools.build_meta
+ """),
+ }
+ build_files(files)
+ build_backend = self.get_build_backend()
+ targz_path = build_backend.build_sdist("temp")
+ with tarfile.open(os.path.join("temp", targz_path)) as tar:
+ assert any('pyproject.toml' in name for name in tar.getnames())
+
+ def test_build_sdist_setup_py_exists(self, tmpdir_cwd):
+ # If build_sdist is called from a script other than setup.py,
+ # ensure setup.py is included
+ build_files(defns[0])
+
+ build_backend = self.get_build_backend()
+ targz_path = build_backend.build_sdist("temp")
+ with tarfile.open(os.path.join("temp", targz_path)) as tar:
+ assert any('setup.py' in name for name in tar.getnames())
+
+ def test_build_sdist_setup_py_manifest_excluded(self, tmpdir_cwd):
+ # Ensure that MANIFEST.in can exclude setup.py
+ files = {
+ 'setup.py': DALS("""
+ __import__('setuptools').setup(
+ name='foo',
+ version='0.0.0',
+ py_modules=['hello']
+ )"""),
+ 'hello.py': '',
+ 'MANIFEST.in': DALS("""
+ exclude setup.py
+ """)
+ }
+
+ build_files(files)
+
+ build_backend = self.get_build_backend()
+ targz_path = build_backend.build_sdist("temp")
+ with tarfile.open(os.path.join("temp", targz_path)) as tar:
+ assert not any('setup.py' in name for name in tar.getnames())
+
+ def test_build_sdist_builds_targz_even_if_zip_indicated(self, tmpdir_cwd):
+ files = {
+ 'setup.py': DALS("""
+ __import__('setuptools').setup(
+ name='foo',
+ version='0.0.0',
+ py_modules=['hello']
+ )"""),
+ 'hello.py': '',
+ 'setup.cfg': DALS("""
+ [sdist]
+ formats=zip
+ """)
+ }
+
+ build_files(files)
+
+ build_backend = self.get_build_backend()
+ build_backend.build_sdist("temp")
+
+ _relative_path_import_files = {
+ 'setup.py': DALS("""
+ __import__('setuptools').setup(
+ name='foo',
+ version=__import__('hello').__version__,
+ py_modules=['hello']
+ )"""),
+ 'hello.py': '__version__ = "0.0.0"',
+ 'setup.cfg': DALS("""
+ [sdist]
+ formats=zip
+ """)
+ }
- dist_info = build_backend.prepare_metadata_for_build_wheel(dist_dir)
+ def test_build_sdist_relative_path_import(self, tmpdir_cwd):
+ build_files(self._relative_path_import_files)
+ build_backend = self.get_build_backend()
+ with pytest.raises(ImportError):
+ build_backend.build_sdist("temp")
+
+ @pytest.mark.parametrize('setup_literal, requirements', [
+ ("'foo'", ['foo']),
+ ("['foo']", ['foo']),
+ (r"'foo\n'", ['foo']),
+ (r"'foo\n\n'", ['foo']),
+ ("['foo', 'bar']", ['foo', 'bar']),
+ (r"'# Has a comment line\nfoo'", ['foo']),
+ (r"'foo # Has an inline comment'", ['foo']),
+ (r"'foo \\\n >=3.0'", ['foo>=3.0']),
+ (r"'foo\nbar'", ['foo', 'bar']),
+ (r"'foo\nbar\n'", ['foo', 'bar']),
+ (r"['foo\n', 'bar\n']", ['foo', 'bar']),
+ ])
+ @pytest.mark.parametrize('use_wheel', [True, False])
+ def test_setup_requires(self, setup_literal, requirements, use_wheel,
+ tmpdir_cwd):
+
+ files = {
+ 'setup.py': DALS("""
+ from setuptools import setup
+
+ setup(
+ name="qux",
+ version="0.0.0",
+ py_modules=["hello.py"],
+ setup_requires={setup_literal},
+ )
+ """).format(setup_literal=setup_literal),
+ 'hello.py': DALS("""
+ def run():
+ print('hello')
+ """),
+ }
- assert os.path.isfile(os.path.join(dist_dir, dist_info, 'METADATA'))
+ build_files(files)
+ build_backend = self.get_build_backend()
-def test_build_sdist_explicit_dist(build_backend):
- # explicitly specifying the dist folder should work
- # the folder sdist_directory and the ``--dist-dir`` can be the same
- dist_dir = os.path.abspath('dist')
- sdist_name = build_backend.build_sdist(dist_dir)
- assert os.path.isfile(os.path.join(dist_dir, sdist_name))
+ if use_wheel:
+ base_requirements = ['wheel']
+ get_requires = build_backend.get_requires_for_build_wheel
+ else:
+ base_requirements = []
+ get_requires = build_backend.get_requires_for_build_sdist
+ # Ensure that the build requirements are properly parsed
+ expected = sorted(base_requirements + requirements)
+ actual = get_requires()
-def test_build_sdist_version_change(build_backend):
- sdist_into_directory = os.path.abspath("out_sdist")
- os.makedirs(sdist_into_directory)
+ assert expected == sorted(actual)
- sdist_name = build_backend.build_sdist(sdist_into_directory)
- assert os.path.isfile(os.path.join(sdist_into_directory, sdist_name))
+ _sys_argv_0_passthrough = {
+ 'setup.py': DALS("""
+ import os
+ import sys
- # if the setup.py changes subsequent call of the build meta should still succeed, given the
- # sdist_directory the frontend specifies is empty
- with open(os.path.abspath("setup.py"), 'rt') as file_handler:
- content = file_handler.read()
- with open(os.path.abspath("setup.py"), 'wt') as file_handler:
- file_handler.write(content.replace("version='0.0.0'", "version='0.0.1'"))
+ __import__('setuptools').setup(
+ name='foo',
+ version='0.0.0',
+ )
- shutil.rmtree(sdist_into_directory)
- os.makedirs(sdist_into_directory)
+ sys_argv = os.path.abspath(sys.argv[0])
+ file_path = os.path.abspath('setup.py')
+ assert sys_argv == file_path
+ """)
+ }
- sdist_name = build_backend.build_sdist("out_sdist")
- assert os.path.isfile(os.path.join(os.path.abspath("out_sdist"), sdist_name))
+ def test_sys_argv_passthrough(self, tmpdir_cwd):
+ build_files(self._sys_argv_0_passthrough)
+ build_backend = self.get_build_backend()
+ with pytest.raises(AssertionError):
+ build_backend.build_sdist("temp")
-def test_build_sdist_setup_py_exists(tmpdir_cwd):
- # If build_sdist is called from a script other than setup.py,
- # ensure setup.py is include
- build_files(defns[0])
- targz_path = build_sdist("temp")
- with tarfile.open(os.path.join("temp", targz_path)) as tar:
- assert any('setup.py' in name for name in tar.getnames())
+class TestBuildMetaLegacyBackend(TestBuildMetaBackend):
+ backend_name = 'setuptools.build_meta:__legacy__'
+ # build_meta_legacy-specific tests
+ def test_build_sdist_relative_path_import(self, tmpdir_cwd):
+ # This must fail in build_meta, but must pass in build_meta_legacy
+ build_files(self._relative_path_import_files)
-def test_build_sdist_setup_py_manifest_excluded(tmpdir_cwd):
- # Ensure that MANIFEST.in can exclude setup.py
- files = {
- 'setup.py': DALS("""
- __import__('setuptools').setup(
- name='foo',
- version='0.0.0',
- py_modules=['hello']
- )"""),
- 'hello.py': '',
- 'MANIFEST.in': DALS("""
- exclude setup.py
- """)
- }
+ build_backend = self.get_build_backend()
+ build_backend.build_sdist("temp")
- build_files(files)
- targz_path = build_sdist("temp")
- with tarfile.open(os.path.join("temp", targz_path)) as tar:
- assert not any('setup.py' in name for name in tar.getnames())
+ def test_sys_argv_passthrough(self, tmpdir_cwd):
+ build_files(self._sys_argv_0_passthrough)
+ build_backend = self.get_build_backend()
+ build_backend.build_sdist("temp")
diff --git a/setuptools/tests/test_build_py.py b/setuptools/tests/test_build_py.py
index cc701ae6..b3a99f56 100644
--- a/setuptools/tests/test_build_py.py
+++ b/setuptools/tests/test_build_py.py
@@ -1,17 +1,9 @@
import os
-import pytest
-
from setuptools.dist import Distribution
-@pytest.yield_fixture
-def tmpdir_as_cwd(tmpdir):
- with tmpdir.as_cwd():
- yield tmpdir
-
-
-def test_directories_in_package_data_glob(tmpdir_as_cwd):
+def test_directories_in_package_data_glob(tmpdir_cwd):
"""
Directories matching the glob in package_data should
not be included in the package data.
diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py
index 736c184d..2fa0b374 100644
--- a/setuptools/tests/test_config.py
+++ b/setuptools/tests/test_config.py
@@ -1,10 +1,17 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
import contextlib
import pytest
+
from distutils.errors import DistutilsOptionError, DistutilsFileError
from mock import patch
from setuptools.dist import Distribution, _Distribution
from setuptools.config import ConfigHandler, read_configuration
+from setuptools.extern.six.moves import configparser
from . import py2_only, py3_only
+from .textwrap import DALS
+
class ErrConfigHandler(ConfigHandler):
"""Erroneous handler. Fails to implement required methods."""
@@ -16,12 +23,14 @@ def make_package_dir(name, base_dir, ns=False):
dir_package = dir_package.mkdir(dir_name)
init_file = None
if not ns:
- init_file = dir_package.join('__init__.py')
- init_file.write('')
+ init_file = dir_package.join('__init__.py')
+ init_file.write('')
return dir_package, init_file
-def fake_env(tmpdir, setup_cfg, setup_py=None, package_path='fake_package'):
+def fake_env(
+ tmpdir, setup_cfg, setup_py=None,
+ encoding='ascii', package_path='fake_package'):
if setup_py is None:
setup_py = (
@@ -31,7 +40,7 @@ def fake_env(tmpdir, setup_cfg, setup_py=None, package_path='fake_package'):
tmpdir.join('setup.py').write(setup_py)
config = tmpdir.join('setup.cfg')
- config.write(setup_cfg)
+ config.write(setup_cfg.encode(encoding), mode='wb')
package_dir, init_file = make_package_dir(package_path, tmpdir)
@@ -146,6 +155,24 @@ class TestMetadata:
assert metadata.download_url == 'http://test.test.com/test/'
assert metadata.maintainer_email == 'test@test.com'
+ def test_license_cfg(self, tmpdir):
+ fake_env(
+ tmpdir,
+ DALS("""
+ [metadata]
+ name=foo
+ version=0.0.1
+ license=Apache 2.0
+ """)
+ )
+
+ with get_dist(tmpdir) as dist:
+ metadata = dist.metadata
+
+ assert metadata.name == "foo"
+ assert metadata.version == "0.0.1"
+ assert metadata.license == "Apache 2.0"
+
def test_file_mixed(self, tmpdir):
fake_env(
@@ -288,7 +315,7 @@ class TestMetadata:
tmpdir.join('fake_package', 'version.txt').write('1.2.3\n4.5.6\n')
with pytest.raises(DistutilsOptionError):
with get_dist(tmpdir) as dist:
- _ = dist.metadata.version
+ dist.metadata.version
def test_version_with_package_dir_simple(self, tmpdir):
@@ -408,6 +435,61 @@ class TestMetadata:
assert metadata.description == 'Some description'
assert metadata.requires == ['some', 'requirement']
+ def test_interpolation(self, tmpdir):
+ 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'
+ )
+ with get_dist(tmpdir):
+ pass
+
+ def test_non_ascii_3(self, tmpdir):
+ 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'
+ )
+ with get_dist(tmpdir) as dist:
+ assert dist.metadata.description == 'éàïôñ'
+
+ def test_not_utf8(self, tmpdir):
+ """
+ Config files encoded not in UTF-8 will fail
+ """
+ fake_env(
+ tmpdir,
+ '# vim: set fileencoding=iso-8859-15 :\n'
+ '[metadata]\n'
+ 'description = éàïôñ\n',
+ encoding='iso-8859-15'
+ )
+ with pytest.raises(UnicodeDecodeError):
+ with get_dist(tmpdir):
+ pass
+
class TestOptions:
@@ -431,7 +513,7 @@ class TestOptions:
'tests_require = mock==0.7.2; pytest\n'
'setup_requires = docutils>=0.3; spack ==1.1, ==1.3; there\n'
'dependency_links = http://some.com/here/1, '
- 'http://some.com/there/2\n'
+ 'http://some.com/there/2\n'
'python_requires = >=1.0, !=2.8\n'
'py_modules = module1, module2\n'
)
@@ -613,7 +695,7 @@ class TestOptions:
)
with get_dist(tmpdir) as dist:
assert set(dist.packages) == set(
- ['fake_package', 'fake_package.sub_two'])
+ ['fake_package', 'fake_package.sub_two'])
@py2_only
def test_find_namespace_directive_fails_on_py2(self, tmpdir):
@@ -639,7 +721,7 @@ class TestOptions:
dir_sub_two, _ = make_package_dir('sub_two', dir_package, ns=True)
with get_dist(tmpdir) as dist:
- assert set(dist.packages) == {
+ assert set(dist.packages) == {
'fake_package', 'fake_package.sub_two', 'fake_package.sub_one'
}
@@ -666,7 +748,7 @@ class TestOptions:
)
with get_dist(tmpdir) as dist:
assert set(dist.packages) == {
- 'fake_package', 'fake_package.sub_two'
+ 'fake_package', 'fake_package.sub_two'
}
def test_extras_require(self, tmpdir):
@@ -691,7 +773,7 @@ class TestOptions:
tmpdir,
'[options.entry_points]\n'
'group1 = point1 = pack.module:func, '
- '.point2 = pack.module2:func_rest [rest]\n'
+ '.point2 = pack.module2:func_rest [rest]\n'
'group2 = point3 = pack.module:func2\n'
)
@@ -737,7 +819,44 @@ class TestOptions:
]
assert sorted(dist.data_files) == sorted(expected)
+ def test_python_requires_simple(self, tmpdir):
+ fake_env(
+ tmpdir,
+ 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("""
+ [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("""
+ [options]
+ python_requires=invalid
+ """),
+ )
+ with pytest.raises(Exception):
+ with get_dist(tmpdir) as dist:
+ dist.parse_config_files()
+
+
saved_dist_init = _Distribution.__init__
+
+
class TestExternalSetters:
# During creation of the setuptools Distribution() object, we call
# the init of the parent distutils Distribution object via
@@ -762,7 +881,7 @@ class TestExternalSetters:
return None
@patch.object(_Distribution, '__init__', autospec=True)
- def test_external_setters(self, mock_parent_init, tmpdir):
+ def test_external_setters(self, mock_parent_init, tmpdir):
mock_parent_init.side_effect = self._fake_distribution_init
dist = Distribution(attrs={
diff --git a/setuptools/tests/test_depends.py b/setuptools/tests/test_depends.py
index e0cfa880..bff1dfb1 100644
--- a/setuptools/tests/test_depends.py
+++ b/setuptools/tests/test_depends.py
@@ -5,12 +5,12 @@ from setuptools import depends
class TestGetModuleConstant:
- def test_basic(self):
- """
- Invoke get_module_constant on a module in
- the test package.
- """
- mod_name = 'setuptools.tests.mod_with_constant'
- val = depends.get_module_constant(mod_name, 'value')
- assert val == 'three, sir!'
- assert 'setuptools.tests.mod_with_constant' not in sys.modules
+ def test_basic(self):
+ """
+ Invoke get_module_constant on a module in
+ the test package.
+ """
+ mod_name = 'setuptools.tests.mod_with_constant'
+ val = depends.get_module_constant(mod_name, 'value')
+ assert val == 'three, sir!'
+ assert 'setuptools.tests.mod_with_constant' not in sys.modules
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index 00d4bd9a..792975fd 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -95,7 +95,7 @@ class TestDevelop:
with io.open(fn) as init_file:
init = init_file.read().strip()
- expected = 'print("foo")' if six.PY3 else 'print "foo"'
+ expected = 'print "foo"' if six.PY2 else 'print("foo")'
assert init == expected
def test_console_scripts(self, tmpdir):
@@ -161,7 +161,7 @@ class TestNamespaces:
reason="https://github.com/pypa/setuptools/issues/851",
)
@pytest.mark.skipif(
- platform.python_implementation() == 'PyPy' and six.PY3,
+ platform.python_implementation() == 'PyPy' and not six.PY2,
reason="https://github.com/pypa/setuptools/issues/1202",
)
def test_namespace_package_importable(self, tmpdir):
diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py
index cf830b43..531ea1b4 100644
--- a/setuptools/tests/test_dist.py
+++ b/setuptools/tests/test_dist.py
@@ -3,7 +3,16 @@
from __future__ import unicode_literals
import io
-from setuptools.dist import DistDeprecationWarning, _get_unpatched
+import collections
+import re
+import functools
+from distutils.errors import DistutilsSetupError
+from setuptools.dist import (
+ _get_unpatched,
+ check_package_data,
+ DistDeprecationWarning,
+)
+from setuptools import sic
from setuptools import Distribution
from setuptools.extern.six.moves.urllib.request import pathname2url
from setuptools.extern.six.moves.urllib_parse import urljoin
@@ -14,6 +23,7 @@ from .test_easy_install import make_nspkg_sdist
import pytest
+
def test_dist_fetch_build_egg(tmpdir):
"""
Check multiple calls to `Distribution.fetch_build_egg` work as expected.
@@ -53,7 +63,8 @@ def test_dist_fetch_build_egg(tmpdir):
dist.fetch_build_egg(r)
for r in reqs
]
- assert [dist.key for dist in resolved_dists if dist] == reqs
+ # noqa below because on Python 2 it causes flakes
+ assert [dist.key for dist in resolved_dists if dist] == reqs # noqa
def test_dist__get_unpatched_deprecated():
@@ -61,73 +72,72 @@ def test_dist__get_unpatched_deprecated():
def __read_test_cases():
- # Metadata version 1.0
- base_attrs = {
- "name": "package",
- "version": "0.0.1",
- "author": "Foo Bar",
- "author_email": "foo@bar.net",
- "long_description": "Long\ndescription",
- "description": "Short description",
- "keywords": ["one", "two"]
- }
-
- def merge_dicts(d1, d2):
- d1 = d1.copy()
- d1.update(d2)
-
- return d1
+ base = dict(
+ name="package",
+ version="0.0.1",
+ author="Foo Bar",
+ author_email="foo@bar.net",
+ long_description="Long\ndescription",
+ description="Short description",
+ keywords=["one", "two"],
+ )
+
+ params = functools.partial(dict, base)
test_cases = [
- ('Metadata version 1.0', base_attrs.copy()),
- ('Metadata version 1.1: Provides', merge_dicts(base_attrs, {
- 'provides': ['package']
- })),
- ('Metadata version 1.1: Obsoletes', merge_dicts(base_attrs, {
- 'obsoletes': ['foo']
- })),
- ('Metadata version 1.1: Classifiers', merge_dicts(base_attrs, {
- 'classifiers': [
+ ('Metadata version 1.0', params()),
+ ('Metadata version 1.1: Provides', params(
+ provides=['package'],
+ )),
+ ('Metadata version 1.1: Obsoletes', params(
+ obsoletes=['foo'],
+ )),
+ ('Metadata version 1.1: Classifiers', params(
+ classifiers=[
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
- 'License :: OSI Approved :: MIT License'
- ]})),
- ('Metadata version 1.1: Download URL', merge_dicts(base_attrs, {
- 'download_url': 'https://example.com'
- })),
- ('Metadata Version 1.2: Requires-Python', merge_dicts(base_attrs, {
- 'python_requires': '>=3.7'
- })),
- pytest.param('Metadata Version 1.2: Project-Url',
- merge_dicts(base_attrs, {
- 'project_urls': {
- 'Foo': 'https://example.bar'
- }
- }), marks=pytest.mark.xfail(
- reason="Issue #1578: project_urls not read"
+ 'License :: OSI Approved :: MIT License',
+ ],
+ )),
+ ('Metadata version 1.1: Download URL', params(
+ download_url='https://example.com',
+ )),
+ ('Metadata Version 1.2: Requires-Python', params(
+ python_requires='>=3.7',
+ )),
+ pytest.param(
+ 'Metadata Version 1.2: Project-Url',
+ params(project_urls=dict(Foo='https://example.bar')),
+ marks=pytest.mark.xfail(
+ reason="Issue #1578: project_urls not read",
+ ),
+ ),
+ ('Metadata Version 2.1: Long Description Content Type', params(
+ long_description_content_type='text/x-rst; charset=UTF-8',
+ )),
+ pytest.param(
+ 'Metadata Version 2.1: Provides Extra',
+ params(provides_extras=['foo', 'bar']),
+ marks=pytest.mark.xfail(reason="provides_extras not read"),
+ ),
+ ('Missing author', dict(
+ name='foo',
+ version='1.0.0',
+ author_email='snorri@sturluson.name',
+ )),
+ ('Missing author e-mail', dict(
+ name='foo',
+ version='1.0.0',
+ author='Snorri Sturluson',
+ )),
+ ('Missing author and e-mail', dict(
+ name='foo',
+ version='1.0.0',
+ )),
+ ('Bypass normalized version', dict(
+ name='foo',
+ version=sic('1.0.0a'),
)),
- ('Metadata Version 2.1: Long Description Content Type',
- merge_dicts(base_attrs, {
- 'long_description_content_type': 'text/x-rst; charset=UTF-8'
- })),
- pytest.param('Metadata Version 2.1: Provides Extra',
- merge_dicts(base_attrs, {
- 'provides_extras': ['foo', 'bar']
- }), marks=pytest.mark.xfail(reason="provides_extras not read")),
- ('Missing author, missing author e-mail',
- {'name': 'foo', 'version': '1.0.0'}),
- ('Missing author',
- {'name': 'foo',
- 'version': '1.0.0',
- 'author_email': 'snorri@sturluson.name'}),
- ('Missing author e-mail',
- {'name': 'foo',
- 'version': '1.0.0',
- 'author': 'Snorri Sturluson'}),
- ('Missing author',
- {'name': 'foo',
- 'version': '1.0.0',
- 'author': 'Snorri Sturluson'}),
]
return test_cases
@@ -260,3 +270,64 @@ def test_maintainer_author(name, attrs, tmpdir):
else:
line = '%s: %s' % (fkey, val)
assert line in pkg_lines_set
+
+
+def test_provides_extras_deterministic_order():
+ extras = collections.OrderedDict()
+ extras['a'] = ['foo']
+ extras['b'] = ['bar']
+ attrs = dict(extras_require=extras)
+ dist = Distribution(attrs)
+ assert dist.metadata.provides_extras == ['a', 'b']
+ attrs['extras_require'] = collections.OrderedDict(
+ reversed(list(attrs['extras_require'].items())))
+ dist = Distribution(attrs)
+ assert dist.metadata.provides_extras == ['b', 'a']
+
+
+CHECK_PACKAGE_DATA_TESTS = (
+ # Valid.
+ ({
+ '': ['*.txt', '*.rst'],
+ 'hello': ['*.msg'],
+ }, None),
+ # Not a dictionary.
+ ((
+ ('', ['*.txt', '*.rst']),
+ ('hello', ['*.msg']),
+ ), (
+ "'package_data' must be a dictionary mapping package"
+ " names to lists of string wildcard patterns"
+ )),
+ # Invalid key type.
+ ({
+ 400: ['*.txt', '*.rst'],
+ }, (
+ "keys of 'package_data' dict must be strings (got 400)"
+ )),
+ # Invalid value type.
+ ({
+ 'hello': str('*.msg'),
+ }, (
+ "\"values of 'package_data' dict\" "
+ "must be a list of strings (got '*.msg')"
+ )),
+ # Invalid value type (generators are single use)
+ ({
+ 'hello': (x for x in "generator"),
+ }, (
+ "\"values of 'package_data' dict\" must be a list of strings "
+ "(got <generator object"
+ )),
+)
+
+
+@pytest.mark.parametrize(
+ 'package_data, expected_message', CHECK_PACKAGE_DATA_TESTS)
+def test_check_package_data(package_data, expected_message):
+ if expected_message is None:
+ assert check_package_data(None, 'package_data', package_data) is None
+ else:
+ with pytest.raises(
+ DistutilsSetupError, match=re.escape(expected_message)):
+ check_package_data(None, str('package_data'), package_data)
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index 2cf65ae7..534392b9 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -15,26 +15,29 @@ import distutils.errors
import io
import zipfile
import mock
-from setuptools.command.easy_install import EasyInstallDeprecationWarning, ScriptWriter, WindowsScriptWriter
import time
+
from setuptools.extern import six
-from setuptools.extern.six.moves import urllib
import pytest
from setuptools import sandbox
from setuptools.sandbox import run_setup
import setuptools.command.easy_install as ei
-from setuptools.command.easy_install import PthDistributions
+from setuptools.command.easy_install import (
+ EasyInstallDeprecationWarning, ScriptWriter, PthDistributions,
+ WindowsScriptWriter,
+)
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
from pkg_resources import normalize_path, working_set
from pkg_resources import Distribution as PRDistribution
-import setuptools.tests.server
+from setuptools.tests.server import MockServer, path_to_url
from setuptools.tests import fail_on_ascii
import pkg_resources
from . import contexts
+from .files import build_files
from .textwrap import DALS
__metaclass__ = type
@@ -287,7 +290,6 @@ class TestEasyInstallTest:
cmd.easy_install(sdist_script)
assert (target / 'mypkg_script').exists()
-
def test_dist_get_script_args_deprecated(self):
with pytest.warns(EasyInstallDeprecationWarning):
ScriptWriter.get_script_args(None, None)
@@ -304,6 +306,7 @@ class TestEasyInstallTest:
with pytest.warns(EasyInstallDeprecationWarning):
WindowsScriptWriter.get_writer()
+
@pytest.mark.filterwarnings('ignore:Unbuilt egg')
class TestPTHFileWriter:
def test_add_from_cwd_site_sets_dirty(self):
@@ -438,35 +441,40 @@ def distutils_package():
yield
+@pytest.fixture
+def mock_index():
+ # set up a server which will simulate an alternate package index.
+ p_index = MockServer()
+ if p_index.server_port == 0:
+ # Some platforms (Jython) don't find a port to which to bind,
+ # so skip test for them.
+ pytest.skip("could not find a valid port")
+ p_index.start()
+ return p_index
+
+
class TestDistutilsPackage:
def test_bdist_egg_available_on_distutils_pkg(self, distutils_package):
run_setup('setup.py', ['bdist_egg'])
class TestSetupRequires:
- def test_setup_requires_honors_fetch_params(self):
+
+ def test_setup_requires_honors_fetch_params(self, mock_index, monkeypatch):
"""
When easy_install installs a source distribution which specifies
setup_requires, it should honor the fetch parameters (such as
- allow-hosts, index-url, and find-links).
+ index-url, and find-links).
"""
- # set up a server which will simulate an alternate package index.
- p_index = setuptools.tests.server.MockServer()
- p_index.start()
- netloc = 1
- p_index_loc = urllib.parse.urlparse(p_index.url)[netloc]
- if p_index_loc.endswith(':0'):
- # Some platforms (Jython) don't find a port to which to bind,
- # so skip this test for them.
- return
+ monkeypatch.setenv(str('PIP_RETRIES'), str('0'))
+ monkeypatch.setenv(str('PIP_TIMEOUT'), str('0'))
with contexts.quiet():
# create an sdist that has a build-time dependency.
with TestSetupRequires.create_sdist() as dist_file:
with contexts.tempdir() as temp_install_dir:
with contexts.environment(PYTHONPATH=temp_install_dir):
ei_params = [
- '--index-url', p_index.url,
- '--allow-hosts', p_index_loc,
+ '--index-url', mock_index.url,
'--exclude-scripts',
'--install-dir', temp_install_dir,
dist_file,
@@ -476,10 +484,8 @@ class TestSetupRequires:
# fail because it doesn't exist.
with pytest.raises(SystemExit):
easy_install_pkg.main(ei_params)
- # there should have been two or three requests to the server
- # (three happens on Python 3.3a)
- assert 2 <= len(p_index.requests) <= 3
- assert p_index.requests[0].path == '/does-not-exist/'
+ # there should have been one requests to the server
+ assert [r.path for r in mock_index.requests] == ['/does-not-exist/']
@staticmethod
@contextlib.contextmanager
@@ -498,7 +504,9 @@ class TestSetupRequires:
version="1.0",
setup_requires = ['does-not-exist'],
)
- """))])
+ """)),
+ ('setup.cfg', ''),
+ ])
yield dist_path
use_setup_cfg = (
@@ -621,7 +629,7 @@ class TestSetupRequires:
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',),
+ use_setup_cfg=use_setup_cfg + ('version',),
)
test_setup_py = os.path.join(test_pkg, 'setup.py')
with contexts.quiet() as (stdout, stderr):
@@ -630,6 +638,208 @@ class TestSetupRequires:
assert len(lines) > 0
assert lines[-1].strip() == '42'
+ def test_setup_requires_honors_pip_env(self, mock_index, monkeypatch):
+ monkeypatch.setenv(str('PIP_RETRIES'), str('0'))
+ monkeypatch.setenv(str('PIP_TIMEOUT'), str('0'))
+ monkeypatch.setenv(str('PIP_INDEX_URL'), mock_index.url)
+ with contexts.save_pkg_resources_state():
+ with contexts.tempdir() as temp_dir:
+ test_pkg = create_setup_requires_package(
+ temp_dir, 'python-xlib', '0.19',
+ setup_attrs=dict(dependency_links=[]))
+ test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
+ with open(test_setup_cfg, 'w') as fp:
+ fp.write(DALS(
+ '''
+ [easy_install]
+ index_url = https://pypi.org/legacy/
+ '''))
+ test_setup_py = os.path.join(test_pkg, 'setup.py')
+ with pytest.raises(distutils.errors.DistutilsError):
+ run_setup(test_setup_py, [str('--version')])
+ assert len(mock_index.requests) == 1
+ assert mock_index.requests[0].path == '/python-xlib/'
+
+ def test_setup_requires_with_pep508_url(self, mock_index, monkeypatch):
+ monkeypatch.setenv(str('PIP_RETRIES'), str('0'))
+ monkeypatch.setenv(str('PIP_TIMEOUT'), str('0'))
+ monkeypatch.setenv(str('PIP_INDEX_URL'), mock_index.url)
+ with contexts.save_pkg_resources_state():
+ with contexts.tempdir() as temp_dir:
+ dep_sdist = os.path.join(temp_dir, 'dep.tar.gz')
+ make_trivial_sdist(dep_sdist, 'dependency', '42')
+ dep_url = path_to_url(dep_sdist, authority='localhost')
+ test_pkg = create_setup_requires_package(
+ temp_dir,
+ # Ignored (overriden by setup_attrs)
+ 'python-xlib', '0.19',
+ setup_attrs=dict(
+ setup_requires='dependency @ %s' % dep_url))
+ test_setup_py = os.path.join(test_pkg, 'setup.py')
+ run_setup(test_setup_py, [str('--version')])
+ assert len(mock_index.requests) == 0
+
+ def test_setup_requires_with_allow_hosts(self, mock_index):
+ ''' The `allow-hosts` option in not supported anymore. '''
+ with contexts.save_pkg_resources_state():
+ with contexts.tempdir() as temp_dir:
+ test_pkg = os.path.join(temp_dir, 'test_pkg')
+ test_setup_py = os.path.join(test_pkg, 'setup.py')
+ test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
+ os.mkdir(test_pkg)
+ with open(test_setup_py, 'w') as fp:
+ fp.write(DALS(
+ '''
+ from setuptools import setup
+ setup(setup_requires='python-xlib')
+ '''))
+ with open(test_setup_cfg, 'w') as fp:
+ fp.write(DALS(
+ '''
+ [easy_install]
+ allow_hosts = *
+ '''))
+ with pytest.raises(distutils.errors.DistutilsError):
+ run_setup(test_setup_py, [str('--version')])
+ assert len(mock_index.requests) == 0
+
+ def test_setup_requires_with_python_requires(self, monkeypatch, tmpdir):
+ ''' Check `python_requires` is honored. '''
+ monkeypatch.setenv(str('PIP_RETRIES'), str('0'))
+ monkeypatch.setenv(str('PIP_TIMEOUT'), str('0'))
+ monkeypatch.setenv(str('PIP_NO_INDEX'), str('1'))
+ monkeypatch.setenv(str('PIP_VERBOSE'), str('1'))
+ dep_1_0_sdist = 'dep-1.0.tar.gz'
+ dep_1_0_url = path_to_url(str(tmpdir / dep_1_0_sdist))
+ dep_1_0_python_requires = '>=2.7'
+ make_python_requires_sdist(
+ str(tmpdir / dep_1_0_sdist), 'dep', '1.0', dep_1_0_python_requires)
+ dep_2_0_sdist = 'dep-2.0.tar.gz'
+ dep_2_0_url = path_to_url(str(tmpdir / dep_2_0_sdist))
+ dep_2_0_python_requires = '!=' + '.'.join(
+ map(str, sys.version_info[:2])) + '.*'
+ make_python_requires_sdist(
+ str(tmpdir / dep_2_0_sdist), 'dep', '2.0', dep_2_0_python_requires)
+ index = tmpdir / 'index.html'
+ index.write_text(DALS(
+ '''
+ <!DOCTYPE html>
+ <html><head><title>Links for dep</title></head>
+ <body>
+ <h1>Links for dep</h1>
+ <a href="{dep_1_0_url}" data-requires-python="{dep_1_0_python_requires}">{dep_1_0_sdist}</a><br/>
+ <a href="{dep_2_0_url}" data-requires-python="{dep_2_0_python_requires}">{dep_2_0_sdist}</a><br/>
+ </body>
+ </html>
+ ''').format( # noqa
+ dep_1_0_url=dep_1_0_url,
+ dep_1_0_sdist=dep_1_0_sdist,
+ dep_1_0_python_requires=dep_1_0_python_requires,
+ dep_2_0_url=dep_2_0_url,
+ dep_2_0_sdist=dep_2_0_sdist,
+ dep_2_0_python_requires=dep_2_0_python_requires,
+ ), 'utf-8')
+ index_url = path_to_url(str(index))
+ with contexts.save_pkg_resources_state():
+ test_pkg = create_setup_requires_package(
+ str(tmpdir),
+ 'python-xlib', '0.19', # Ignored (overriden by setup_attrs).
+ setup_attrs=dict(
+ setup_requires='dep', dependency_links=[index_url]))
+ test_setup_py = os.path.join(test_pkg, 'setup.py')
+ run_setup(test_setup_py, [str('--version')])
+ eggs = list(map(str, pkg_resources.find_distributions(
+ os.path.join(test_pkg, '.eggs'))))
+ assert eggs == ['dep 1.0']
+
+ @pytest.mark.parametrize(
+ 'use_legacy_installer,with_dependency_links_in_setup_py',
+ itertools.product((False, True), (False, True)))
+ def test_setup_requires_with_find_links_in_setup_cfg(
+ self, monkeypatch, use_legacy_installer,
+ with_dependency_links_in_setup_py):
+ monkeypatch.setenv(str('PIP_RETRIES'), str('0'))
+ monkeypatch.setenv(str('PIP_TIMEOUT'), str('0'))
+ with contexts.save_pkg_resources_state():
+ with contexts.tempdir() as temp_dir:
+ make_trivial_sdist(
+ os.path.join(temp_dir, 'python-xlib-42.tar.gz'),
+ 'python-xlib',
+ '42')
+ test_pkg = os.path.join(temp_dir, 'test_pkg')
+ test_setup_py = os.path.join(test_pkg, 'setup.py')
+ test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
+ os.mkdir(test_pkg)
+ with open(test_setup_py, 'w') as fp:
+ if with_dependency_links_in_setup_py:
+ dependency_links = [os.path.join(temp_dir, 'links')]
+ else:
+ dependency_links = []
+ fp.write(DALS(
+ '''
+ from setuptools import installer, setup
+ if {use_legacy_installer}:
+ installer.fetch_build_egg = installer._legacy_fetch_build_egg
+ setup(setup_requires='python-xlib==42',
+ dependency_links={dependency_links!r})
+ ''').format(use_legacy_installer=use_legacy_installer, # noqa
+ dependency_links=dependency_links))
+ with open(test_setup_cfg, 'w') as fp:
+ fp.write(DALS(
+ '''
+ [easy_install]
+ index_url = {index_url}
+ find_links = {find_links}
+ ''').format(index_url=os.path.join(temp_dir, 'index'),
+ find_links=temp_dir))
+ run_setup(test_setup_py, [str('--version')])
+
+ def test_setup_requires_with_transitive_extra_dependency(
+ self, monkeypatch):
+ # Use case: installing a package with a build dependency on
+ # an already installed `dep[extra]`, which in turn depends
+ # on `extra_dep` (whose is not already installed).
+ with contexts.save_pkg_resources_state():
+ with contexts.tempdir() as temp_dir:
+ # Create source distribution for `extra_dep`.
+ make_trivial_sdist(
+ os.path.join(temp_dir, 'extra_dep-1.0.tar.gz'),
+ 'extra_dep', '1.0')
+ # Create source tree for `dep`.
+ dep_pkg = os.path.join(temp_dir, 'dep')
+ os.mkdir(dep_pkg)
+ build_files({
+ 'setup.py':
+ DALS("""
+ import setuptools
+ setuptools.setup(
+ name='dep', version='2.0',
+ extras_require={'extra': ['extra_dep']},
+ )
+ """),
+ 'setup.cfg': '',
+ }, prefix=dep_pkg)
+ # "Install" dep.
+ run_setup(
+ os.path.join(dep_pkg, 'setup.py'), [str('dist_info')])
+ working_set.add_entry(dep_pkg)
+ # Create source tree for test package.
+ test_pkg = os.path.join(temp_dir, 'test_pkg')
+ test_setup_py = os.path.join(test_pkg, 'setup.py')
+ os.mkdir(test_pkg)
+ with open(test_setup_py, 'w') as fp:
+ fp.write(DALS(
+ '''
+ from setuptools import installer, setup
+ setup(setup_requires='dep[extra]')
+ '''))
+ # Check...
+ monkeypatch.setenv(str('PIP_FIND_LINKS'), str(temp_dir))
+ monkeypatch.setenv(str('PIP_NO_INDEX'), str('1'))
+ monkeypatch.setenv(str('PIP_RETRIES'), str('0'))
+ monkeypatch.setenv(str('PIP_TIMEOUT'), str('0'))
+ run_setup(test_setup_py, [str('--version')])
+
def make_trivial_sdist(dist_path, distname, version):
"""
@@ -645,7 +855,9 @@ def make_trivial_sdist(dist_path, distname, version):
name=%r,
version=%r
)
- """ % (distname, version)))])
+ """ % (distname, version))),
+ ('setup.cfg', ''),
+ ])
def make_nspkg_sdist(dist_path, distname, version):
@@ -681,12 +893,32 @@ def make_nspkg_sdist(dist_path, distname, version):
make_sdist(dist_path, files)
+def make_python_requires_sdist(dist_path, distname, version, python_requires):
+ make_sdist(dist_path, [
+ (
+ 'setup.py',
+ DALS("""\
+ import setuptools
+ setuptools.setup(
+ name={name!r},
+ version={version!r},
+ python_requires={python_requires!r},
+ )
+ """).format(
+ name=distname, version=version,
+ python_requires=python_requires)),
+ ('setup.cfg', ''),
+ ])
+
+
def make_sdist(dist_path, files):
"""
Create a simple sdist tarball at dist_path, containing the files
listed in ``files`` as ``(filename, content)`` tuples.
"""
+ # Distributions with only one file don't play well with pip.
+ assert len(files) > 1
with tarfile.open(dist_path, 'w:gz') as dist:
for filename, content in files:
file_bytes = io.BytesIO(content.encode('utf-8'))
@@ -719,8 +951,8 @@ def create_setup_requires_package(path, distname='foobar', version='0.1',
test_pkg = os.path.join(path, 'test_pkg')
os.mkdir(test_pkg)
+ # setup.cfg
if use_setup_cfg:
- test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
options = []
metadata = []
for name in use_setup_cfg:
@@ -732,27 +964,29 @@ def create_setup_requires_package(path, distname='foobar', version='0.1',
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')
+ test_setup_cfg_contents = DALS(
+ """
+ [metadata]
+ {metadata}
+ [options]
+ {options}
+ """
+ ).format(
+ options='\n'.join(options),
+ metadata='\n'.join(metadata),
+ )
+ else:
+ test_setup_cfg_contents = ''
+ with open(os.path.join(test_pkg, 'setup.cfg'), 'w') as f:
+ f.write(test_setup_cfg_contents)
+ # setup.py
if setup_py_template is None:
setup_py_template = DALS("""\
import setuptools
setuptools.setup(**%r)
""")
- with open(test_setup_py, 'w') as f:
+ with open(os.path.join(test_pkg, 'setup.py'), 'w') as f:
f.write(setup_py_template % test_setup_attrs)
foobar_path = os.path.join(path, '%s-%s.tar.gz' % (distname, version))
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index f97b3f1d..109f9135 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -1,4 +1,3 @@
-import datetime
import sys
import ast
import os
@@ -7,7 +6,9 @@ import re
import stat
import time
-from setuptools.command.egg_info import egg_info, manifest_maker, EggInfoDeprecationWarning, get_pkg_info_revision
+from setuptools.command.egg_info import (
+ egg_info, manifest_maker, EggInfoDeprecationWarning, get_pkg_info_revision,
+)
from setuptools.dist import Distribution
from setuptools.extern.six.moves import map
@@ -148,6 +149,37 @@ class TestEggInfo:
]
assert sorted(actual) == expected
+ def test_license_is_a_string(self, tmpdir_cwd, env):
+ setup_config = DALS("""
+ [metadata]
+ name=foo
+ version=0.0.1
+ license=file:MIT
+ """)
+
+ setup_script = DALS("""
+ from setuptools import setup
+
+ setup()
+ """)
+
+ build_files({'setup.py': setup_script,
+ 'setup.cfg': setup_config})
+
+ # This command should fail with a ValueError, but because it's
+ # currently configured to use a subprocess, the actual traceback
+ # object is lost and we need to parse it from stderr
+ with pytest.raises(AssertionError) as exc:
+ self._run_egg_info_command(tmpdir_cwd, env)
+
+ # Hopefully this is not too fragile: the only argument to the
+ # assertion error should be a traceback, ending with:
+ # ValueError: ....
+ #
+ # assert not 1
+ tb = exc.value.args[0].split('\n')
+ assert tb[-3].lstrip().startswith('ValueError')
+
def test_rebuilt(self, tmpdir_cwd, env):
"""Ensure timestamps are updated when the command is re-run."""
self._create_project()
@@ -486,6 +518,259 @@ class TestEggInfo:
pkg_info_text = pkginfo_file.read()
assert 'Provides-Extra:' not in pkg_info_text
+ @pytest.mark.parametrize("files, license_in_sources", [
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE
+ """),
+ 'LICENSE': "Test license"
+ }, True), # with license
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = INVALID_LICENSE
+ """),
+ 'LICENSE': "Test license"
+ }, False), # with an invalid license
+ ({
+ 'setup.cfg': DALS("""
+ """),
+ 'LICENSE': "Test license"
+ }, False), # no license_file attribute
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE
+ """),
+ 'MANIFEST.in': "exclude LICENSE",
+ 'LICENSE': "Test license"
+ }, False) # license file is manually excluded
+ ])
+ def test_setup_cfg_license_file(
+ self, tmpdir_cwd, env, files, license_in_sources):
+ self._create_project()
+ build_files(files)
+
+ environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)])
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+
+ with open(os.path.join(egg_info_dir, 'SOURCES.txt')) as sources_file:
+ sources_text = sources_file.read()
+
+ if license_in_sources:
+ assert 'LICENSE' in sources_text
+ else:
+ assert 'LICENSE' not in sources_text
+ # for invalid license test
+ assert 'INVALID_LICENSE' not in sources_text
+
+ @pytest.mark.parametrize("files, incl_licenses, excl_licenses", [
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files =
+ LICENSE-ABC
+ LICENSE-XYZ
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, ['LICENSE-ABC', 'LICENSE-XYZ'], []), # with licenses
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files = LICENSE-ABC, LICENSE-XYZ
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, ['LICENSE-ABC', 'LICENSE-XYZ'], []), # with commas
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files =
+ LICENSE-ABC
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, ['LICENSE-ABC'], ['LICENSE-XYZ']), # with one license
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files =
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, [], ['LICENSE-ABC', 'LICENSE-XYZ']), # empty
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files = LICENSE-XYZ
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, ['LICENSE-XYZ'], ['LICENSE-ABC']), # on same line
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files =
+ LICENSE-ABC
+ INVALID_LICENSE
+ """),
+ 'LICENSE-ABC': "Test license"
+ }, ['LICENSE-ABC'], ['INVALID_LICENSE']), # with an invalid license
+ ({
+ 'setup.cfg': DALS("""
+ """),
+ 'LICENSE': "Test license"
+ }, [], ['LICENSE']), # no license_files attribute
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files = LICENSE
+ """),
+ 'MANIFEST.in': "exclude LICENSE",
+ 'LICENSE': "Test license"
+ }, [], ['LICENSE']), # license file is manually excluded
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_files =
+ LICENSE-ABC
+ LICENSE-XYZ
+ """),
+ 'MANIFEST.in': "exclude LICENSE-XYZ",
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, ['LICENSE-ABC'], ['LICENSE-XYZ']) # subset is manually excluded
+ ])
+ def test_setup_cfg_license_files(
+ self, tmpdir_cwd, env, files, incl_licenses, excl_licenses):
+ self._create_project()
+ build_files(files)
+
+ environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)])
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+
+ with open(os.path.join(egg_info_dir, 'SOURCES.txt')) as sources_file:
+ sources_lines = list(line.strip() for line in sources_file)
+
+ for lf in incl_licenses:
+ assert sources_lines.count(lf) == 1
+
+ for lf in excl_licenses:
+ assert sources_lines.count(lf) == 0
+
+ @pytest.mark.parametrize("files, incl_licenses, excl_licenses", [
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file =
+ license_files =
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, [], ['LICENSE-ABC', 'LICENSE-XYZ']), # both empty
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file =
+ LICENSE-ABC
+ LICENSE-XYZ
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-XYZ': "XYZ license"
+ # license_file is still singular
+ }, [], ['LICENSE-ABC', 'LICENSE-XYZ']),
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE-ABC
+ license_files =
+ LICENSE-XYZ
+ LICENSE-PQR
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-PQR': "PQR license",
+ 'LICENSE-XYZ': "XYZ license"
+ }, ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], []), # combined
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE-ABC
+ license_files =
+ LICENSE-ABC
+ LICENSE-XYZ
+ LICENSE-PQR
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-PQR': "PQR license",
+ 'LICENSE-XYZ': "XYZ license"
+ # duplicate license
+ }, ['LICENSE-ABC', 'LICENSE-PQR', 'LICENSE-XYZ'], []),
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE-ABC
+ license_files =
+ LICENSE-XYZ
+ """),
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-PQR': "PQR license",
+ 'LICENSE-XYZ': "XYZ license"
+ # combined subset
+ }, ['LICENSE-ABC', 'LICENSE-XYZ'], ['LICENSE-PQR']),
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE-ABC
+ license_files =
+ LICENSE-XYZ
+ LICENSE-PQR
+ """),
+ 'LICENSE-PQR': "Test license"
+ # with invalid licenses
+ }, ['LICENSE-PQR'], ['LICENSE-ABC', 'LICENSE-XYZ']),
+ ({
+ 'setup.cfg': DALS("""
+ [metadata]
+ license_file = LICENSE-ABC
+ license_files =
+ LICENSE-PQR
+ LICENSE-XYZ
+ """),
+ 'MANIFEST.in': "exclude LICENSE-ABC\nexclude LICENSE-PQR",
+ 'LICENSE-ABC': "ABC license",
+ 'LICENSE-PQR': "PQR license",
+ 'LICENSE-XYZ': "XYZ license"
+ # manually excluded
+ }, ['LICENSE-XYZ'], ['LICENSE-ABC', 'LICENSE-PQR'])
+ ])
+ def test_setup_cfg_license_file_license_files(
+ self, tmpdir_cwd, env, files, incl_licenses, excl_licenses):
+ self._create_project()
+ build_files(files)
+
+ environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)])
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+
+ with open(os.path.join(egg_info_dir, 'SOURCES.txt')) as sources_file:
+ sources_lines = list(line.strip() for line in sources_file)
+
+ for lf in incl_licenses:
+ assert sources_lines.count(lf) == 1
+
+ for lf in excl_licenses:
+ assert sources_lines.count(lf) == 0
+
def test_long_description_content_type(self, tmpdir_cwd, env):
# Test that specifying a `long_description_content_type` keyword arg to
# the `setup` function results in writing a `Description-Content-Type`
@@ -541,6 +826,7 @@ class TestEggInfo:
assert expected_line in pkg_info_lines
expected_line = 'Project-URL: Link Two, https://example.com/two/'
assert expected_line in pkg_info_lines
+ assert 'Metadata-Version: 1.2' in pkg_info_lines
def test_python_requires_egg_info(self, tmpdir_cwd, env):
self._setup_script_with_requires(
@@ -597,8 +883,8 @@ class TestEggInfo:
data_stream=1,
env=environ,
)
- if code:
- raise AssertionError(data)
+ assert not code, data
+
if output:
assert output in data
@@ -620,3 +906,49 @@ class TestEggInfo:
def test_get_pkg_info_revision_deprecated(self):
pytest.warns(EggInfoDeprecationWarning, get_pkg_info_revision)
+
+ EGG_INFO_TESTS = (
+ # Check for issue #1136: invalid string type when
+ # reading declarative `setup.cfg` under Python 2.
+ {
+ 'setup.py': DALS(
+ """
+ from setuptools import setup
+ setup(
+ name="foo",
+ )
+ """),
+ 'setup.cfg': DALS(
+ """
+ [options]
+ package_dir =
+ = src
+ """),
+ 'src': {},
+ },
+ # Check Unicode can be used in `setup.py` under Python 2.
+ {
+ 'setup.py': DALS(
+ """
+ # -*- coding: utf-8 -*-
+ from __future__ import unicode_literals
+ from setuptools import setup, find_packages
+ setup(
+ name="foo",
+ package_dir={'': 'src'},
+ )
+ """),
+ 'src': {},
+ }
+ )
+
+ @pytest.mark.parametrize('package_files', EGG_INFO_TESTS)
+ def test_egg_info(self, tmpdir_cwd, env, package_files):
+ """
+ """
+ build_files(package_files)
+ code, data = environment.run_setup_py(
+ cmd=['egg_info'],
+ data_stream=1,
+ )
+ assert not code, data
diff --git a/setuptools/tests/test_extern.py b/setuptools/tests/test_extern.py
new file mode 100644
index 00000000..3519a680
--- /dev/null
+++ b/setuptools/tests/test_extern.py
@@ -0,0 +1,22 @@
+import importlib
+import pickle
+
+from setuptools import Distribution
+from setuptools.extern import ordered_set
+from setuptools.tests import py3_only
+
+
+def test_reimport_extern():
+ ordered_set2 = importlib.import_module(ordered_set.__name__)
+ assert ordered_set is ordered_set2
+
+
+def test_orderedset_pickle_roundtrip():
+ o1 = ordered_set.OrderedSet([1, 2, 5])
+ o2 = pickle.loads(pickle.dumps(o1))
+ assert o1 == o2
+
+
+@py3_only
+def test_distribution_picklable():
+ pickle.loads(pickle.dumps(Distribution()))
diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py
index b08f91c7..ab26b4f1 100644
--- a/setuptools/tests/test_find_packages.py
+++ b/setuptools/tests/test_find_packages.py
@@ -12,10 +12,10 @@ from . import py3_only
from setuptools.extern.six import PY3
from setuptools import find_packages
if PY3:
- from setuptools import find_namespace_packages
+ from setuptools import find_namespace_packages
-# modeled after CPython's test.support.can_symlink
+# modeled after CPython's test.support.can_symlink
def can_symlink():
TESTFN = tempfile.mktemp()
symlink_path = TESTFN + "can_symlink"
@@ -164,12 +164,14 @@ class TestFindPackages:
def test_pep420_ns_package_no_includes(self):
packages = find_namespace_packages(
self.dist_dir, exclude=['pkg.subpkg.assets'])
- self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
+ self._assert_packages(
+ packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
@py3_only
def test_pep420_ns_package_no_includes_or_excludes(self):
packages = find_namespace_packages(self.dist_dir)
- expected = ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
+ expected = [
+ 'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
self._assert_packages(packages, expected)
@py3_only
@@ -185,4 +187,3 @@ class TestFindPackages:
shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
packages = find_namespace_packages(self.dist_dir)
self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
-
diff --git a/setuptools/tests/test_glibc.py b/setuptools/tests/test_glibc.py
deleted file mode 100644
index 795fdc56..00000000
--- a/setuptools/tests/test_glibc.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import warnings
-
-import pytest
-
-from setuptools.glibc import check_glibc_version
-
-__metaclass__ = type
-
-
-@pytest.fixture(params=[
- "2.20",
- # used by "linaro glibc", see gh-3588
- "2.20-2014.11",
- # weird possibilities that I just made up
- "2.20+dev",
- "2.20-custom",
- "2.20.1",
- ])
-def two_twenty(request):
- return request.param
-
-
-@pytest.fixture(params=["asdf", "", "foo.bar"])
-def bad_string(request):
- return request.param
-
-
-class TestGlibc:
- def test_manylinux1_check_glibc_version(self, two_twenty):
- """
- Test that the check_glibc_version function is robust against weird
- glibc version strings.
- """
- assert check_glibc_version(two_twenty, 2, 15)
- assert check_glibc_version(two_twenty, 2, 20)
- assert not check_glibc_version(two_twenty, 2, 21)
- assert not check_glibc_version(two_twenty, 3, 15)
- assert not check_glibc_version(two_twenty, 1, 15)
-
- def test_bad_versions(self, bad_string):
- """
- For unparseable strings, warn and return False
- """
- with warnings.catch_warnings(record=True) as ws:
- warnings.filterwarnings("always")
- assert not check_glibc_version(bad_string, 2, 5)
- for w in ws:
- if "Expected glibc version with" in str(w.message):
- break
- else:
- # Didn't find the warning we were expecting
- assert False
diff --git a/setuptools/tests/test_install_scripts.py b/setuptools/tests/test_install_scripts.py
index 727ad65b..4338c792 100644
--- a/setuptools/tests/test_install_scripts.py
+++ b/setuptools/tests/test_install_scripts.py
@@ -64,7 +64,8 @@ class TestInstallScripts:
@pytest.mark.skipif(sys.platform == 'win32', reason='non-Windows only')
def test_executable_with_spaces_escaping_unix(self, tmpdir):
"""
- Ensure that shebang on Unix is not quoted, even when a value with spaces
+ Ensure that shebang on Unix is not quoted, even when
+ a value with spaces
is specified using --executable.
"""
expected = '#!%s\n' % self.unix_spaces_exe
@@ -77,7 +78,8 @@ class TestInstallScripts:
@pytest.mark.skipif(sys.platform != 'win32', reason='Windows only')
def test_executable_arg_escaping_win32(self, tmpdir):
"""
- Ensure that shebang on Windows is quoted when getting a path with spaces
+ Ensure that shebang on Windows is quoted when
+ getting a path with spaces
from --executable, that is itself properly quoted.
"""
expected = '#!"%s"\n' % self.win32_exe
diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py
index 3a9a6c50..f1a27f8b 100644
--- a/setuptools/tests/test_integration.py
+++ b/setuptools/tests/test_integration.py
@@ -6,6 +6,11 @@ Try to install a few packages.
import glob
import os
import sys
+import re
+import subprocess
+import functools
+import tarfile
+import zipfile
from setuptools.extern.six.moves import urllib
import pytest
@@ -59,7 +64,7 @@ def install_context(request, tmpdir, monkeypatch):
monkeypatch.setattr('site.USER_BASE', user_base.strpath)
monkeypatch.setattr('site.USER_SITE', user_site.strpath)
monkeypatch.setattr('sys.path', sys.path + [install_dir.strpath])
- monkeypatch.setenv('PYTHONPATH', os.path.pathsep.join(sys.path))
+ monkeypatch.setenv(str('PYTHONPATH'), str(os.path.pathsep.join(sys.path)))
# Set up the command for performing the installation.
dist = Distribution()
@@ -114,15 +119,12 @@ def test_pyuri(install_context):
assert os.path.exists(os.path.join(pyuri.location, 'pyuri', 'uri.regex'))
-import re
-import subprocess
-import functools
-import tarfile, zipfile
+build_deps = ['appdirs', 'packaging', 'pyparsing', 'six']
-build_deps = ['appdirs', 'packaging', 'pyparsing', 'six']
@pytest.mark.parametrize("build_dep", build_deps)
-@pytest.mark.skipif(sys.version_info < (3, 6), reason='run only on late versions')
+@pytest.mark.skipif(
+ sys.version_info < (3, 6), reason='run only on late versions')
def test_build_deps_on_distutils(request, tmpdir_factory, build_dep):
"""
All setuptools build dependencies must build without
@@ -139,7 +141,9 @@ def test_build_deps_on_distutils(request, tmpdir_factory, build_dep):
allowed_unknowns = [
'test_suite',
'tests_require',
+ 'python_requires',
'install_requires',
+ 'long_description_content_type',
]
assert not match or match.group(1).strip('"\'') in allowed_unknowns
@@ -147,15 +151,18 @@ def test_build_deps_on_distutils(request, tmpdir_factory, build_dep):
def install(pkg_dir, install_dir):
with open(os.path.join(pkg_dir, 'setuptools.py'), 'w') as breaker:
breaker.write('raise ImportError()')
- cmd = [sys.executable, 'setup.py', 'install', '--prefix', install_dir]
- env = dict(os.environ, PYTHONPATH=pkg_dir)
- output = subprocess.check_output(cmd, cwd=pkg_dir, env=env, stderr=subprocess.STDOUT)
+ cmd = [sys.executable, 'setup.py', 'install', '--prefix', str(install_dir)]
+ env = dict(os.environ, PYTHONPATH=str(pkg_dir))
+ output = subprocess.check_output(
+ cmd, cwd=pkg_dir, env=env, stderr=subprocess.STDOUT)
return output.decode('utf-8')
def download_and_extract(request, req, target):
- cmd = [sys.executable, '-m', 'pip', 'download', '--no-deps',
- '--no-binary', ':all:', req]
+ cmd = [
+ sys.executable, '-m', 'pip', 'download', '--no-deps',
+ '--no-binary', ':all:', req,
+ ]
output = subprocess.check_output(cmd, encoding='utf-8')
filename = re.search('Saved (.*)', output).group(1)
request.addfinalizer(functools.partial(os.remove, filename))
diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py
index 5edfbea0..2a0e9c86 100644
--- a/setuptools/tests/test_manifest.py
+++ b/setuptools/tests/test_manifest.py
@@ -15,7 +15,6 @@ from setuptools.command.egg_info import FileList, egg_info, translate_pattern
from setuptools.dist import Distribution
from setuptools.extern import six
from setuptools.tests.textwrap import DALS
-from . import py3_only
import pytest
@@ -74,7 +73,9 @@ translate_specs = [
# Glob matching
('*.txt', ['foo.txt', 'bar.txt'], ['foo/foo.txt']),
- ('dir/*.txt', ['dir/foo.txt', 'dir/bar.txt', 'dir/.txt'], ['notdir/foo.txt']),
+ (
+ 'dir/*.txt',
+ ['dir/foo.txt', 'dir/bar.txt', 'dir/.txt'], ['notdir/foo.txt']),
('*/*.py', ['bin/start.py'], []),
('docs/page-?.txt', ['docs/page-9.txt'], ['docs/page-10.txt']),
@@ -243,77 +244,77 @@ class TestManifestTest(TempDirTestCase):
def test_exclude(self):
"""Include everything in app/ except the text files"""
- l = make_local_path
+ ml = make_local_path
self.make_manifest(
"""
include app/*
exclude app/*.txt
""")
- files = default_files | set([l('app/c.rst')])
+ files = default_files | set([ml('app/c.rst')])
assert files == self.get_files()
def test_include_multiple(self):
"""Include with multiple patterns."""
- l = make_local_path
+ ml = make_local_path
self.make_manifest("include app/*.txt app/static/*")
files = default_files | set([
- l('app/a.txt'), l('app/b.txt'),
- l('app/static/app.js'), l('app/static/app.js.map'),
- l('app/static/app.css'), l('app/static/app.css.map')])
+ ml('app/a.txt'), ml('app/b.txt'),
+ ml('app/static/app.js'), ml('app/static/app.js.map'),
+ ml('app/static/app.css'), ml('app/static/app.css.map')])
assert files == self.get_files()
def test_graft(self):
"""Include the whole app/static/ directory."""
- l = make_local_path
+ ml = make_local_path
self.make_manifest("graft app/static")
files = default_files | set([
- l('app/static/app.js'), l('app/static/app.js.map'),
- l('app/static/app.css'), l('app/static/app.css.map')])
+ ml('app/static/app.js'), ml('app/static/app.js.map'),
+ ml('app/static/app.css'), ml('app/static/app.css.map')])
assert files == self.get_files()
def test_graft_glob_syntax(self):
"""Include the whole app/static/ directory."""
- l = make_local_path
+ ml = make_local_path
self.make_manifest("graft */static")
files = default_files | set([
- l('app/static/app.js'), l('app/static/app.js.map'),
- l('app/static/app.css'), l('app/static/app.css.map')])
+ ml('app/static/app.js'), ml('app/static/app.js.map'),
+ ml('app/static/app.css'), ml('app/static/app.css.map')])
assert files == self.get_files()
def test_graft_global_exclude(self):
"""Exclude all *.map files in the project."""
- l = make_local_path
+ ml = make_local_path
self.make_manifest(
"""
graft app/static
global-exclude *.map
""")
files = default_files | set([
- l('app/static/app.js'), l('app/static/app.css')])
+ ml('app/static/app.js'), ml('app/static/app.css')])
assert files == self.get_files()
def test_global_include(self):
"""Include all *.rst, *.js, and *.css files in the whole tree."""
- l = make_local_path
+ ml = make_local_path
self.make_manifest(
"""
global-include *.rst *.js *.css
""")
files = default_files | set([
- '.hidden.rst', 'testing.rst', l('app/c.rst'),
- l('app/static/app.js'), l('app/static/app.css')])
+ '.hidden.rst', 'testing.rst', ml('app/c.rst'),
+ ml('app/static/app.js'), ml('app/static/app.css')])
assert files == self.get_files()
def test_graft_prune(self):
"""Include all files in app/, except for the whole app/static/ dir."""
- l = make_local_path
+ ml = make_local_path
self.make_manifest(
"""
graft app
prune app/static
""")
files = default_files | set([
- l('app/a.txt'), l('app/b.txt'), l('app/c.rst')])
+ ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')])
assert files == self.get_files()
@@ -369,7 +370,7 @@ class TestFileListTest(TempDirTestCase):
def test_process_template_line(self):
# testing all MANIFEST.in template patterns
file_list = FileList()
- l = make_local_path
+ ml = make_local_path
# simulated file list
self.make_files([
@@ -377,16 +378,16 @@ class TestFileListTest(TempDirTestCase):
'buildout.cfg',
# filelist does not filter out VCS directories,
# it's sdist that does
- l('.hg/last-message.txt'),
- l('global/one.txt'),
- l('global/two.txt'),
- l('global/files.x'),
- l('global/here.tmp'),
- l('f/o/f.oo'),
- l('dir/graft-one'),
- l('dir/dir2/graft2'),
- l('dir3/ok'),
- l('dir3/sub/ok.txt'),
+ ml('.hg/last-message.txt'),
+ ml('global/one.txt'),
+ ml('global/two.txt'),
+ ml('global/files.x'),
+ ml('global/here.tmp'),
+ ml('f/o/f.oo'),
+ ml('dir/graft-one'),
+ ml('dir/dir2/graft2'),
+ ml('dir3/ok'),
+ ml('dir3/sub/ok.txt'),
])
MANIFEST_IN = DALS("""\
@@ -413,12 +414,12 @@ class TestFileListTest(TempDirTestCase):
'buildout.cfg',
'four.txt',
'ok',
- l('.hg/last-message.txt'),
- l('dir/graft-one'),
- l('dir/dir2/graft2'),
- l('f/o/f.oo'),
- l('global/one.txt'),
- l('global/two.txt'),
+ ml('.hg/last-message.txt'),
+ ml('dir/graft-one'),
+ ml('dir/dir2/graft2'),
+ ml('f/o/f.oo'),
+ ml('global/one.txt'),
+ ml('global/two.txt'),
]
file_list.sort()
@@ -475,10 +476,10 @@ class TestFileListTest(TempDirTestCase):
assert False, "Should have thrown an error"
def test_include(self):
- l = make_local_path
+ ml = make_local_path
# include
file_list = FileList()
- self.make_files(['a.py', 'b.txt', l('d/c.py')])
+ self.make_files(['a.py', 'b.txt', ml('d/c.py')])
file_list.process_template_line('include *.py')
file_list.sort()
@@ -491,42 +492,42 @@ class TestFileListTest(TempDirTestCase):
self.assertWarnings()
def test_exclude(self):
- l = make_local_path
+ ml = make_local_path
# exclude
file_list = FileList()
- file_list.files = ['a.py', 'b.txt', l('d/c.py')]
+ file_list.files = ['a.py', 'b.txt', ml('d/c.py')]
file_list.process_template_line('exclude *.py')
file_list.sort()
- assert file_list.files == ['b.txt', l('d/c.py')]
+ assert file_list.files == ['b.txt', ml('d/c.py')]
self.assertNoWarnings()
file_list.process_template_line('exclude *.rb')
file_list.sort()
- assert file_list.files == ['b.txt', l('d/c.py')]
+ assert file_list.files == ['b.txt', ml('d/c.py')]
self.assertWarnings()
def test_global_include(self):
- l = make_local_path
+ ml = make_local_path
# global-include
file_list = FileList()
- self.make_files(['a.py', 'b.txt', l('d/c.py')])
+ self.make_files(['a.py', 'b.txt', ml('d/c.py')])
file_list.process_template_line('global-include *.py')
file_list.sort()
- assert file_list.files == ['a.py', l('d/c.py')]
+ assert file_list.files == ['a.py', ml('d/c.py')]
self.assertNoWarnings()
file_list.process_template_line('global-include *.rb')
file_list.sort()
- assert file_list.files == ['a.py', l('d/c.py')]
+ assert file_list.files == ['a.py', ml('d/c.py')]
self.assertWarnings()
def test_global_exclude(self):
- l = make_local_path
+ ml = make_local_path
# global-exclude
file_list = FileList()
- file_list.files = ['a.py', 'b.txt', l('d/c.py')]
+ file_list.files = ['a.py', 'b.txt', ml('d/c.py')]
file_list.process_template_line('global-exclude *.py')
file_list.sort()
@@ -539,65 +540,65 @@ class TestFileListTest(TempDirTestCase):
self.assertWarnings()
def test_recursive_include(self):
- l = make_local_path
+ ml = make_local_path
# recursive-include
file_list = FileList()
- self.make_files(['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')])
+ self.make_files(['a.py', ml('d/b.py'), ml('d/c.txt'), ml('d/d/e.py')])
file_list.process_template_line('recursive-include d *.py')
file_list.sort()
- assert file_list.files == [l('d/b.py'), l('d/d/e.py')]
+ assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
self.assertNoWarnings()
file_list.process_template_line('recursive-include e *.py')
file_list.sort()
- assert file_list.files == [l('d/b.py'), l('d/d/e.py')]
+ assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
self.assertWarnings()
def test_recursive_exclude(self):
- l = make_local_path
+ ml = make_local_path
# recursive-exclude
file_list = FileList()
- file_list.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
+ file_list.files = ['a.py', ml('d/b.py'), ml('d/c.txt'), ml('d/d/e.py')]
file_list.process_template_line('recursive-exclude d *.py')
file_list.sort()
- assert file_list.files == ['a.py', l('d/c.txt')]
+ assert file_list.files == ['a.py', ml('d/c.txt')]
self.assertNoWarnings()
file_list.process_template_line('recursive-exclude e *.py')
file_list.sort()
- assert file_list.files == ['a.py', l('d/c.txt')]
+ assert file_list.files == ['a.py', ml('d/c.txt')]
self.assertWarnings()
def test_graft(self):
- l = make_local_path
+ ml = make_local_path
# graft
file_list = FileList()
- self.make_files(['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')])
+ self.make_files(['a.py', ml('d/b.py'), ml('d/d/e.py'), ml('f/f.py')])
file_list.process_template_line('graft d')
file_list.sort()
- assert file_list.files == [l('d/b.py'), l('d/d/e.py')]
+ assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
self.assertNoWarnings()
file_list.process_template_line('graft e')
file_list.sort()
- assert file_list.files == [l('d/b.py'), l('d/d/e.py')]
+ assert file_list.files == [ml('d/b.py'), ml('d/d/e.py')]
self.assertWarnings()
def test_prune(self):
- l = make_local_path
+ ml = make_local_path
# prune
file_list = FileList()
- file_list.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
+ file_list.files = ['a.py', ml('d/b.py'), ml('d/d/e.py'), ml('f/f.py')]
file_list.process_template_line('prune d')
file_list.sort()
- assert file_list.files == ['a.py', l('f/f.py')]
+ assert file_list.files == ['a.py', ml('f/f.py')]
self.assertNoWarnings()
file_list.process_template_line('prune e')
file_list.sort()
- assert file_list.files == ['a.py', l('f/f.py')]
+ assert file_list.files == ['a.py', ml('f/f.py')]
self.assertWarnings()
diff --git a/setuptools/tests/test_msvc.py b/setuptools/tests/test_msvc.py
index 32d7a907..24e38ea8 100644
--- a/setuptools/tests/test_msvc.py
+++ b/setuptools/tests/test_msvc.py
@@ -49,7 +49,8 @@ def mock_reg(hkcu=None, hklm=None):
for k in hive if k.startswith(key.lower())
)
- return mock.patch.multiple(distutils.msvc9compiler.Reg,
+ return mock.patch.multiple(
+ distutils.msvc9compiler.Reg,
read_keys=read_keys, read_values=read_values)
@@ -61,7 +62,7 @@ class TestModulePatch:
"""
key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir'
- key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\installdir'
+ key_64 = key_32.replace(r'\microsoft', r'\wow6432node\microsoft')
def test_patched(self):
"Test the module is actually patched"
diff --git a/setuptools/tests/test_msvc14.py b/setuptools/tests/test_msvc14.py
new file mode 100644
index 00000000..7833aab4
--- /dev/null
+++ b/setuptools/tests/test_msvc14.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+"""
+Tests for msvc support module (msvc14 unit tests).
+"""
+
+import os
+from distutils.errors import DistutilsPlatformError
+import pytest
+import sys
+
+
+@pytest.mark.skipif(sys.platform != "win32",
+ reason="These tests are only for win32")
+class TestMSVC14:
+ """Python 3.8 "distutils/tests/test_msvccompiler.py" backport"""
+ def test_no_compiler(self):
+ import setuptools.msvc as _msvccompiler
+ # makes sure query_vcvarsall raises
+ # a DistutilsPlatformError if the compiler
+ # is not found
+
+ def _find_vcvarsall(plat_spec):
+ return None, None
+
+ old_find_vcvarsall = _msvccompiler._msvc14_find_vcvarsall
+ _msvccompiler._msvc14_find_vcvarsall = _find_vcvarsall
+ try:
+ pytest.raises(DistutilsPlatformError,
+ _msvccompiler._msvc14_get_vc_env,
+ 'wont find this version')
+ finally:
+ _msvccompiler._msvc14_find_vcvarsall = old_find_vcvarsall
+
+ @pytest.mark.skipif(sys.version_info[0] < 3,
+ reason="Unicode requires encode/decode on Python 2")
+ def test_get_vc_env_unicode(self):
+ import setuptools.msvc as _msvccompiler
+
+ test_var = 'ṰḖṤṪ┅ṼẨṜ'
+ test_value = '₃⁴₅'
+
+ # Ensure we don't early exit from _get_vc_env
+ old_distutils_use_sdk = os.environ.pop('DISTUTILS_USE_SDK', None)
+ os.environ[test_var] = test_value
+ try:
+ env = _msvccompiler._msvc14_get_vc_env('x86')
+ assert test_var.lower() in env
+ assert test_value == env[test_var.lower()]
+ finally:
+ os.environ.pop(test_var)
+ if old_distutils_use_sdk:
+ os.environ['DISTUTILS_USE_SDK'] = old_distutils_use_sdk
+
+ def test_get_vc2017(self):
+ import setuptools.msvc as _msvccompiler
+
+ # This function cannot be mocked, so pass it if we find VS 2017
+ # and mark it skipped if we do not.
+ version, path = _msvccompiler._msvc14_find_vc2017()
+ if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in [
+ 'Visual Studio 2017'
+ ]:
+ assert version
+ if version:
+ assert version >= 15
+ assert os.path.isdir(path)
+ else:
+ pytest.skip("VS 2017 is not installed")
+
+ def test_get_vc2015(self):
+ import setuptools.msvc as _msvccompiler
+
+ # This function cannot be mocked, so pass it if we find VS 2015
+ # and mark it skipped if we do not.
+ version, path = _msvccompiler._msvc14_find_vc2015()
+ if os.environ.get('APPVEYOR_BUILD_WORKER_IMAGE', '') in [
+ 'Visual Studio 2015', 'Visual Studio 2017'
+ ]:
+ assert version
+ if version:
+ assert version >= 14
+ assert os.path.isdir(path)
+ else:
+ pytest.skip("VS 2015 is not installed")
diff --git a/setuptools/tests/test_namespaces.py b/setuptools/tests/test_namespaces.py
index 670ccee9..f937d981 100644
--- a/setuptools/tests/test_namespaces.py
+++ b/setuptools/tests/test_namespaces.py
@@ -1,6 +1,5 @@
from __future__ import absolute_import, unicode_literals
-import os
import sys
import subprocess
diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py
index 63b92946..60d968fd 100644
--- a/setuptools/tests/test_packageindex.py
+++ b/setuptools/tests/test_packageindex.py
@@ -6,6 +6,8 @@ import distutils.errors
from setuptools.extern import six
from setuptools.extern.six.moves import urllib, http_client
+import mock
+import pytest
import pkg_resources
import setuptools.package_index
@@ -42,7 +44,10 @@ class TestPackageIndex:
hosts=('www.example.com',)
)
- url = 'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk'
+ url = (
+ 'url:%20https://svn.plone.org/svn'
+ '/collective/inquant.contentmirror.plone/trunk'
+ )
try:
v = index.open_url(url)
except Exception as v:
@@ -61,9 +66,9 @@ class TestPackageIndex:
index.opener = _urlopen
url = 'http://example.com'
try:
- v = index.open_url(url)
- except Exception as v:
- assert 'line' in str(v)
+ index.open_url(url)
+ except Exception as exc:
+ assert 'line' in str(exc)
else:
raise AssertionError('Should have raise here!')
@@ -81,7 +86,11 @@ class TestPackageIndex:
index.open_url(url)
except distutils.errors.DistutilsError as error:
msg = six.text_type(error)
- assert 'nonnumeric port' in msg or 'getaddrinfo failed' in msg or 'Name or service not known' in msg
+ assert (
+ 'nonnumeric port' in msg
+ or 'getaddrinfo failed' in msg
+ or 'Name or service not known' in msg
+ )
return
raise RuntimeError("Did not raise")
@@ -223,6 +232,61 @@ class TestPackageIndex:
assert dists[0].version == ''
assert dists[1].version == vc
+ def test_download_git_with_rev(self, tmpdir):
+ url = 'git+https://github.example/group/project@master#egg=foo'
+ index = setuptools.package_index.PackageIndex()
+
+ with mock.patch("os.system") as os_system_mock:
+ result = index.download(url, str(tmpdir))
+
+ os_system_mock.assert_called()
+
+ expected_dir = str(tmpdir / 'project@master')
+ expected = (
+ 'git clone --quiet '
+ 'https://github.example/group/project {expected_dir}'
+ ).format(**locals())
+ first_call_args = os_system_mock.call_args_list[0][0]
+ assert first_call_args == (expected,)
+
+ tmpl = 'git -C {expected_dir} checkout --quiet master'
+ expected = tmpl.format(**locals())
+ assert os_system_mock.call_args_list[1][0] == (expected,)
+ assert result == expected_dir
+
+ def test_download_git_no_rev(self, tmpdir):
+ url = 'git+https://github.example/group/project#egg=foo'
+ index = setuptools.package_index.PackageIndex()
+
+ with mock.patch("os.system") as os_system_mock:
+ result = index.download(url, str(tmpdir))
+
+ os_system_mock.assert_called()
+
+ expected_dir = str(tmpdir / 'project')
+ expected = (
+ 'git clone --quiet '
+ 'https://github.example/group/project {expected_dir}'
+ ).format(**locals())
+ os_system_mock.assert_called_once_with(expected)
+
+ def test_download_svn(self, tmpdir):
+ url = 'svn+https://svn.example/project#egg=foo'
+ index = setuptools.package_index.PackageIndex()
+
+ with pytest.warns(UserWarning):
+ with mock.patch("os.system") as os_system_mock:
+ result = index.download(url, str(tmpdir))
+
+ os_system_mock.assert_called()
+
+ expected_dir = str(tmpdir / 'project')
+ expected = (
+ 'svn checkout -q '
+ 'svn+https://svn.example/project {expected_dir}'
+ ).format(**locals())
+ os_system_mock.assert_called_once_with(expected)
+
class TestContentCheckers:
def test_md5(self):
diff --git a/setuptools/tests/test_pep425tags.py b/setuptools/tests/test_pep425tags.py
deleted file mode 100644
index f558a0d8..00000000
--- a/setuptools/tests/test_pep425tags.py
+++ /dev/null
@@ -1,168 +0,0 @@
-import sys
-
-import pytest
-from mock import patch
-
-from setuptools import pep425tags
-
-__metaclass__ = type
-
-
-class TestPEP425Tags:
-
- def mock_get_config_var(self, **kwd):
- """
- Patch sysconfig.get_config_var for arbitrary keys.
- """
- get_config_var = pep425tags.sysconfig.get_config_var
-
- def _mock_get_config_var(var):
- if var in kwd:
- return kwd[var]
- return get_config_var(var)
- return _mock_get_config_var
-
- def abi_tag_unicode(self, flags, config_vars):
- """
- Used to test ABI tags, verify correct use of the `u` flag
- """
- config_vars.update({'SOABI': None})
- base = pep425tags.get_abbr_impl() + pep425tags.get_impl_ver()
-
- if sys.version_info < (3, 3):
- config_vars.update({'Py_UNICODE_SIZE': 2})
- mock_gcf = self.mock_get_config_var(**config_vars)
- with patch('setuptools.pep425tags.sysconfig.get_config_var', mock_gcf):
- abi_tag = pep425tags.get_abi_tag()
- assert abi_tag == base + flags
-
- config_vars.update({'Py_UNICODE_SIZE': 4})
- mock_gcf = self.mock_get_config_var(**config_vars)
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- abi_tag = pep425tags.get_abi_tag()
- assert abi_tag == base + flags + 'u'
-
- else:
- # On Python >= 3.3, UCS-4 is essentially permanently enabled, and
- # Py_UNICODE_SIZE is None. SOABI on these builds does not include
- # the 'u' so manual SOABI detection should not do so either.
- config_vars.update({'Py_UNICODE_SIZE': None})
- mock_gcf = self.mock_get_config_var(**config_vars)
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- abi_tag = pep425tags.get_abi_tag()
- assert abi_tag == base + flags
-
- def test_broken_sysconfig(self):
- """
- Test that pep425tags still works when sysconfig is broken.
- Can be a problem on Python 2.7
- Issue #1074.
- """
- def raises_ioerror(var):
- raise IOError("I have the wrong path!")
-
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- raises_ioerror):
- with pytest.warns(RuntimeWarning):
- assert len(pep425tags.get_supported())
-
- def test_no_hyphen_tag(self):
- """
- Test that no tag contains a hyphen.
- """
- mock_gcf = self.mock_get_config_var(SOABI='cpython-35m-darwin')
-
- with patch('setuptools.pep425tags.sysconfig.get_config_var',
- mock_gcf):
- supported = pep425tags.get_supported()
-
- for (py, abi, plat) in supported:
- assert '-' not in py
- assert '-' not in abi
- assert '-' not in plat
-
- def test_manual_abi_noflags(self):
- """
- Test that no flags are set on a non-PyDebug, non-Pymalloc ABI tag.
- """
- self.abi_tag_unicode('', {'Py_DEBUG': False, 'WITH_PYMALLOC': False})
-
- def test_manual_abi_d_flag(self):
- """
- Test that the `d` flag is set on a PyDebug, non-Pymalloc ABI tag.
- """
- self.abi_tag_unicode('d', {'Py_DEBUG': True, 'WITH_PYMALLOC': False})
-
- def test_manual_abi_m_flag(self):
- """
- Test that the `m` flag is set on a non-PyDebug, Pymalloc ABI tag.
- """
- self.abi_tag_unicode('m', {'Py_DEBUG': False, 'WITH_PYMALLOC': True})
-
- def test_manual_abi_dm_flags(self):
- """
- Test that the `dm` flags are set on a PyDebug, Pymalloc ABI tag.
- """
- self.abi_tag_unicode('dm', {'Py_DEBUG': True, 'WITH_PYMALLOC': True})
-
-
-class TestManylinux1Tags:
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_x86_64')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- def test_manylinux1_compatible_on_linux_x86_64(self):
- """
- Test that manylinux1 is enabled on linux_x86_64
- """
- assert pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_i686')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- def test_manylinux1_compatible_on_linux_i686(self):
- """
- Test that manylinux1 is enabled on linux_i686
- """
- assert pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_x86_64')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: False)
- def test_manylinux1_2(self):
- """
- Test that manylinux1 is disabled with incompatible glibc
- """
- assert not pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'arm6vl')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- def test_manylinux1_3(self):
- """
- Test that manylinux1 is disabled on arm6vl
- """
- assert not pep425tags.is_manylinux1_compatible()
-
- @patch('setuptools.pep425tags.get_platform', lambda: 'linux_x86_64')
- @patch('setuptools.glibc.have_compatible_glibc',
- lambda major, minor: True)
- @patch('sys.platform', 'linux2')
- def test_manylinux1_tag_is_first(self):
- """
- Test that the more specific tag manylinux1 comes first.
- """
- groups = {}
- for pyimpl, abi, arch in pep425tags.get_supported():
- groups.setdefault((pyimpl, abi), []).append(arch)
-
- for arches in groups.values():
- if arches == ['any']:
- continue
- # Expect the most specific arch first:
- if len(arches) == 3:
- assert arches == ['manylinux1_x86_64', 'linux_x86_64', 'any']
- else:
- assert arches == ['manylinux1_x86_64', 'linux_x86_64']
diff --git a/setuptools/tests/test_register.py b/setuptools/tests/test_register.py
index 96114595..98605806 100644
--- a/setuptools/tests/test_register.py
+++ b/setuptools/tests/test_register.py
@@ -1,43 +1,22 @@
-import mock
-from distutils import log
-
-import pytest
-
from setuptools.command.register import register
from setuptools.dist import Distribution
+from setuptools.errors import RemovedCommandError
+try:
+ from unittest import mock
+except ImportError:
+ import mock
-class TestRegisterTest:
- def test_warns_deprecation(self):
- dist = Distribution()
-
- cmd = register(dist)
- cmd.run_command = mock.Mock()
- cmd.send_metadata = mock.Mock()
- cmd.announce = mock.Mock()
-
- cmd.run()
+import pytest
- cmd.announce.assert_called_with(
- "WARNING: Registering is deprecated, use twine to upload instead "
- "(https://pypi.org/p/twine/)",
- log.WARN
- )
- def test_warns_deprecation_when_raising(self):
+class TestRegister:
+ def test_register_exception(self):
+ """Ensure that the register command has been properly removed."""
dist = Distribution()
+ dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())]
cmd = register(dist)
- cmd.run_command = mock.Mock()
- cmd.send_metadata = mock.Mock()
- cmd.send_metadata.side_effect = Exception
- cmd.announce = mock.Mock()
- with pytest.raises(Exception):
+ with pytest.raises(RemovedCommandError):
cmd.run()
-
- cmd.announce.assert_called_with(
- "WARNING: Registering is deprecated, use twine to upload instead "
- "(https://pypi.org/p/twine/)",
- log.WARN
- )
diff --git a/setuptools/tests/test_sandbox.py b/setuptools/tests/test_sandbox.py
index d8675422..99398cdb 100644
--- a/setuptools/tests/test_sandbox.py
+++ b/setuptools/tests/test_sandbox.py
@@ -26,7 +26,8 @@ class TestSandbox:
"""
It should be possible to execute a setup.py with a Byte Order Mark
"""
- target = pkg_resources.resource_filename(__name__,
+ target = pkg_resources.resource_filename(
+ __name__,
'script-with-bom.py')
namespace = types.ModuleType('namespace')
setuptools.sandbox._execfile(target, vars(namespace))
diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py
index d2c4e0cf..0bea53df 100644
--- a/setuptools/tests/test_sdist.py
+++ b/setuptools/tests/test_sdist.py
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
"""sdist tests"""
+from __future__ import print_function, unicode_literals
+
import os
-import shutil
import sys
import tempfile
import unicodedata
@@ -50,7 +51,7 @@ def quiet():
# Convert to POSIX path
def posix(path):
- if six.PY3 and not isinstance(path, str):
+ if not six.PY2 and not isinstance(path, str):
return path.replace(os.sep.encode('ascii'), b'/')
else:
return path.replace(os.sep, '/')
@@ -89,30 +90,28 @@ fail_on_latin1_encoded_filenames = pytest.mark.xfail(
)
+def touch(path):
+ path.write_text('', encoding='utf-8')
+
+
class TestSdistTest:
- def setup_method(self, method):
- self.temp_dir = tempfile.mkdtemp()
- with open(os.path.join(self.temp_dir, 'setup.py'), 'w') as f:
- f.write(SETUP_PY)
+ @pytest.fixture(autouse=True)
+ def source_dir(self, tmpdir):
+ (tmpdir / 'setup.py').write_text(SETUP_PY, encoding='utf-8')
# Set up the rest of the test package
- test_pkg = os.path.join(self.temp_dir, 'sdist_test')
- os.mkdir(test_pkg)
- data_folder = os.path.join(self.temp_dir, "d")
- os.mkdir(data_folder)
+ test_pkg = tmpdir / 'sdist_test'
+ test_pkg.mkdir()
+ data_folder = tmpdir / 'd'
+ data_folder.mkdir()
# *.rst was not included in package_data, so c.rst should not be
# automatically added to the manifest when not under version control
- for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst',
- os.path.join(data_folder, "e.dat")]:
- # Just touch the files; their contents are irrelevant
- open(os.path.join(test_pkg, fname), 'w').close()
-
- self.old_cwd = os.getcwd()
- os.chdir(self.temp_dir)
+ for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']:
+ touch(test_pkg / fname)
+ touch(data_folder / 'e.dat')
- def teardown_method(self, method):
- os.chdir(self.old_cwd)
- shutil.rmtree(self.temp_dir)
+ with tmpdir.as_cwd():
+ yield
def test_package_data_in_sdist(self):
"""Regression test for pull request #4: ensures that files listed in
@@ -175,14 +174,14 @@ class TestSdistTest:
manifest = cmd.filelist.files
assert 'setup.py' not in manifest
- def test_defaults_case_sensitivity(self):
+ def test_defaults_case_sensitivity(self, tmpdir):
"""
Make sure default files (README.*, etc.) are added in a case-sensitive
way to avoid problems with packages built on Windows.
"""
- open(os.path.join(self.temp_dir, 'readme.rst'), 'w').close()
- open(os.path.join(self.temp_dir, 'SETUP.cfg'), 'w').close()
+ touch(tmpdir / 'readme.rst')
+ touch(tmpdir / 'SETUP.cfg')
dist = Distribution(SETUP_ATTRS)
# the extension deliberately capitalized for this test
@@ -230,10 +229,6 @@ class TestSdistTest:
u_contents = contents.decode('UTF-8')
# The manifest should contain the UTF-8 filename
- if six.PY2:
- fs_enc = sys.getfilesystemencoding()
- filename = filename.decode(fs_enc)
-
assert posix(filename) in u_contents
@py3_only
@@ -334,7 +329,7 @@ class TestSdistTest:
cmd.read_manifest()
# The filelist should contain the UTF-8 filename
- if six.PY3:
+ if not six.PY2:
filename = filename.decode('utf-8')
assert filename in cmd.filelist.files
@@ -374,7 +369,7 @@ class TestSdistTest:
@fail_on_latin1_encoded_filenames
def test_sdist_with_utf8_encoded_filename(self):
# Test for #303.
- dist = Distribution(SETUP_ATTRS)
+ dist = Distribution(self.make_strings(SETUP_ATTRS))
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
@@ -388,7 +383,7 @@ class TestSdistTest:
if sys.platform == 'darwin':
filename = decompose(filename)
- if six.PY3:
+ if not six.PY2:
fs_enc = sys.getfilesystemencoding()
if sys.platform == 'win32':
@@ -405,10 +400,19 @@ class TestSdistTest:
else:
assert filename in cmd.filelist.files
+ @classmethod
+ def make_strings(cls, item):
+ if isinstance(item, dict):
+ return {
+ key: cls.make_strings(value) for key, value in item.items()}
+ if isinstance(item, list):
+ return list(map(cls.make_strings, item))
+ return str(item)
+
@fail_on_latin1_encoded_filenames
def test_sdist_with_latin1_encoded_filename(self):
# Test for #303.
- dist = Distribution(SETUP_ATTRS)
+ dist = Distribution(self.make_strings(SETUP_ATTRS))
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
@@ -421,7 +425,19 @@ class TestSdistTest:
with quiet():
cmd.run()
- if six.PY3:
+ if six.PY2:
+ # Under Python 2 there seems to be no decoded string in the
+ # filelist. However, due to decode and encoding of the
+ # file name to get utf-8 Manifest the latin1 maybe excluded
+ try:
+ # fs_enc should match how one is expect the decoding to
+ # be proformed for the manifest output.
+ fs_enc = sys.getfilesystemencoding()
+ filename.decode(fs_enc)
+ assert filename in cmd.filelist.files
+ except UnicodeDecodeError:
+ filename not in cmd.filelist.files
+ else:
# not all windows systems have a default FS encoding of cp1252
if sys.platform == 'win32':
# Latin-1 is similar to Windows-1252 however
@@ -436,18 +452,36 @@ class TestSdistTest:
# The Latin-1 filename should have been skipped
filename = filename.decode('latin-1')
filename not in cmd.filelist.files
- else:
- # Under Python 2 there seems to be no decoded string in the
- # filelist. However, due to decode and encoding of the
- # file name to get utf-8 Manifest the latin1 maybe excluded
- try:
- # fs_enc should match how one is expect the decoding to
- # be proformed for the manifest output.
- fs_enc = sys.getfilesystemencoding()
- filename.decode(fs_enc)
- assert filename in cmd.filelist.files
- except UnicodeDecodeError:
- filename not in cmd.filelist.files
+
+ def test_pyproject_toml_in_sdist(self, tmpdir):
+ """
+ Check if pyproject.toml is included in source distribution if present
+ """
+ touch(tmpdir / 'pyproject.toml')
+ dist = Distribution(SETUP_ATTRS)
+ dist.script_name = 'setup.py'
+ cmd = sdist(dist)
+ cmd.ensure_finalized()
+ with quiet():
+ cmd.run()
+ manifest = cmd.filelist.files
+ assert 'pyproject.toml' in manifest
+
+ def test_pyproject_toml_excluded(self, tmpdir):
+ """
+ Check that pyproject.toml can excluded even if present
+ """
+ touch(tmpdir / 'pyproject.toml')
+ with open('MANIFEST.in', 'w') as mts:
+ print('exclude pyproject.toml', file=mts)
+ dist = Distribution(SETUP_ATTRS)
+ dist.script_name = 'setup.py'
+ cmd = sdist(dist)
+ cmd.ensure_finalized()
+ with quiet():
+ cmd.run()
+ manifest = cmd.filelist.files
+ assert 'pyproject.toml' not in manifest
def test_default_revctrl():
diff --git a/setuptools/tests/test_setopt.py b/setuptools/tests/test_setopt.py
new file mode 100644
index 00000000..1b038954
--- /dev/null
+++ b/setuptools/tests/test_setopt.py
@@ -0,0 +1,36 @@
+# coding: utf-8
+
+from __future__ import unicode_literals
+
+import io
+
+import six
+
+from setuptools.command import setopt
+from setuptools.extern.six.moves import configparser
+
+
+class TestEdit:
+ @staticmethod
+ def parse_config(filename):
+ parser = configparser.ConfigParser()
+ with io.open(filename, encoding='utf-8') as reader:
+ (parser.readfp if six.PY2 else parser.read_file)(reader)
+ return parser
+
+ @staticmethod
+ def write_text(file, content):
+ with io.open(file, 'wb') as strm:
+ strm.write(content.encode('utf-8'))
+
+ def test_utf8_encoding_retained(self, tmpdir):
+ """
+ When editing a file, non-ASCII characters encoded in
+ UTF-8 should be retained.
+ """
+ config = tmpdir.join('setup.cfg')
+ self.write_text(str(config), '[names]\njaraco=джарако')
+ setopt.edit_config(str(config), dict(names=dict(other='yes')))
+ parser = self.parse_config(str(config))
+ assert parser.get('names', 'jaraco') == 'джарако'
+ assert parser.get('names', 'other') == 'yes'
diff --git a/setuptools/tests/test_setuptools.py b/setuptools/tests/test_setuptools.py
index 7aae3a16..08d263ae 100644
--- a/setuptools/tests/test_setuptools.py
+++ b/setuptools/tests/test_setuptools.py
@@ -4,7 +4,7 @@ import sys
import os
import distutils.core
import distutils.cmd
-from distutils.errors import DistutilsOptionError, DistutilsPlatformError
+from distutils.errors import DistutilsOptionError
from distutils.errors import DistutilsSetupError
from distutils.core import Extension
from distutils.version import LooseVersion
@@ -14,7 +14,6 @@ import pytest
import setuptools
import setuptools.dist
import setuptools.depends as dep
-from setuptools import Feature
from setuptools.depends import Require
from setuptools.extern import six
@@ -77,7 +76,8 @@ class TestDepends:
from json import __version__
assert dep.get_module_constant('json', '__version__') == __version__
assert dep.get_module_constant('sys', 'version') == sys.version
- assert dep.get_module_constant('setuptools.tests.test_setuptools', '__doc__') == __doc__
+ assert dep.get_module_constant(
+ 'setuptools.tests.test_setuptools', '__doc__') == __doc__
@needs_bytecode
def testRequire(self):
@@ -107,6 +107,11 @@ class TestDepends:
assert not req.is_present()
assert not req.is_current()
+ @needs_bytecode
+ def test_require_present(self):
+ # In #1896, this test was failing for months with the only
+ # complaint coming from test runners (not end users).
+ # TODO: Evaluate if this code is needed at all.
req = Require('Tests', None, 'tests', homepage="http://example.com")
assert req.format is None
assert req.attribute is None
@@ -210,84 +215,6 @@ class TestDistro:
self.dist.exclude(package_dir=['q'])
-@pytest.mark.filterwarnings('ignore:Features are deprecated')
-class TestFeatures:
- def setup_method(self, method):
- self.req = Require('Distutils', '1.0.3', 'distutils')
- self.dist = makeSetup(
- features={
- 'foo': Feature("foo", standard=True, require_features=['baz', self.req]),
- 'bar': Feature("bar", standard=True, packages=['pkg.bar'],
- py_modules=['bar_et'], remove=['bar.ext'],
- ),
- 'baz': Feature(
- "baz", optional=False, packages=['pkg.baz'],
- scripts=['scripts/baz_it'],
- libraries=[('libfoo', 'foo/foofoo.c')]
- ),
- 'dwim': Feature("DWIM", available=False, remove='bazish'),
- },
- script_args=['--without-bar', 'install'],
- packages=['pkg.bar', 'pkg.foo'],
- py_modules=['bar_et', 'bazish'],
- ext_modules=[Extension('bar.ext', ['bar.c'])]
- )
-
- def testDefaults(self):
- assert not Feature(
- "test", standard=True, remove='x', available=False
- ).include_by_default()
- assert Feature("test", standard=True, remove='x').include_by_default()
- # Feature must have either kwargs, removes, or require_features
- with pytest.raises(DistutilsSetupError):
- Feature("test")
-
- def testAvailability(self):
- with pytest.raises(DistutilsPlatformError):
- self.dist.features['dwim'].include_in(self.dist)
-
- def testFeatureOptions(self):
- dist = self.dist
- assert (
- ('with-dwim', None, 'include DWIM') in dist.feature_options
- )
- assert (
- ('without-dwim', None, 'exclude DWIM (default)') in dist.feature_options
- )
- assert (
- ('with-bar', None, 'include bar (default)') in dist.feature_options
- )
- assert (
- ('without-bar', None, 'exclude bar') in dist.feature_options
- )
- assert dist.feature_negopt['without-foo'] == 'with-foo'
- assert dist.feature_negopt['without-bar'] == 'with-bar'
- assert dist.feature_negopt['without-dwim'] == 'with-dwim'
- assert ('without-baz' not in dist.feature_negopt)
-
- def testUseFeatures(self):
- dist = self.dist
- assert dist.with_foo == 1
- assert dist.with_bar == 0
- assert dist.with_baz == 1
- assert ('bar_et' not in dist.py_modules)
- assert ('pkg.bar' not in dist.packages)
- assert ('pkg.baz' in dist.packages)
- assert ('scripts/baz_it' in dist.scripts)
- assert (('libfoo', 'foo/foofoo.c') in dist.libraries)
- assert dist.ext_modules == []
- assert dist.require_features == [self.req]
-
- # If we ask for bar, it should fail because we explicitly disabled
- # it on the command line
- with pytest.raises(DistutilsOptionError):
- dist.include_feature('bar')
-
- def testFeatureWithInvalidRemove(self):
- with pytest.raises(SystemExit):
- makeSetup(features={'x': Feature('x', remove='y')})
-
-
class TestCommandTests:
def testTestIsCommand(self):
test_cmd = makeSetup().get_command_obj('test')
diff --git a/setuptools/tests/test_test.py b/setuptools/tests/test_test.py
index 8d1425e1..8ee70a7e 100644
--- a/setuptools/tests/test_test.py
+++ b/setuptools/tests/test_test.py
@@ -1,10 +1,10 @@
-# -*- coding: UTF-8 -*-
+# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+import mock
from distutils import log
import os
-import sys
import pytest
@@ -12,7 +12,7 @@ from setuptools.command.test import test
from setuptools.dist import Distribution
from .textwrap import DALS
-from . import contexts
+
SETUP_PY = DALS("""
from setuptools import setup
@@ -86,9 +86,7 @@ def test_test(capfd):
dist.script_name = 'setup.py'
cmd = test(dist)
cmd.ensure_finalized()
- # The test runner calls sys.exit
- with contexts.suppress_exceptions(SystemExit):
- cmd.run()
+ cmd.run()
out, err = capfd.readouterr()
assert out == 'Foo\n'
@@ -120,8 +118,55 @@ def test_tests_are_run_once(capfd):
dist.script_name = 'setup.py'
cmd = test(dist)
cmd.ensure_finalized()
- # The test runner calls sys.exit
- with contexts.suppress_exceptions(SystemExit):
- cmd.run()
+ cmd.run()
out, err = capfd.readouterr()
assert out == 'Foo\n'
+
+
+@pytest.mark.usefixtures('sample_test')
+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')
+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
diff --git a/setuptools/tests/test_upload.py b/setuptools/tests/test_upload.py
index cc0e8a0d..7586cb26 100644
--- a/setuptools/tests/test_upload.py
+++ b/setuptools/tests/test_upload.py
@@ -1,214 +1,22 @@
-import mock
-import os
-import re
-
-from distutils import log
-from distutils.errors import DistutilsError
-from distutils.version import StrictVersion
-
-import pytest
-
from setuptools.command.upload import upload
from setuptools.dist import Distribution
-from setuptools.extern import six
-
-
-def _parse_upload_body(body):
- boundary = u'\r\n----------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
- entries = []
- name_re = re.compile(u'^Content-Disposition: form-data; name="([^\"]+)"')
-
- for entry in body.split(boundary):
- pair = entry.split(u'\r\n\r\n')
- if not len(pair) == 2:
- continue
-
- key, value = map(six.text_type.strip, pair)
- m = name_re.match(key)
- if m is not None:
- key = m.group(1)
-
- entries.append((key, value))
-
- return entries
-
-
-@pytest.fixture
-def patched_upload(tmpdir):
- class Fix:
- def __init__(self, cmd, urlopen):
- self.cmd = cmd
- self.urlopen = urlopen
-
- def __iter__(self):
- return iter((self.cmd, self.urlopen))
-
- def get_uploaded_metadata(self):
- request = self.urlopen.call_args_list[0][0][0]
- body = request.data.decode('utf-8')
- entries = dict(_parse_upload_body(body))
-
- return entries
+from setuptools.errors import RemovedCommandError
- class ResponseMock(mock.Mock):
- def getheader(self, name, default=None):
- """Mocked getheader method for response object"""
- return {
- 'content-type': 'text/plain; charset=utf-8',
- }.get(name.lower(), default)
+try:
+ from unittest import mock
+except ImportError:
+ import mock
- with mock.patch('setuptools.command.upload.urlopen') as urlopen:
- urlopen.return_value = ResponseMock()
- urlopen.return_value.getcode.return_value = 200
- urlopen.return_value.read.return_value = b''
-
- content = os.path.join(str(tmpdir), "content_data")
-
- with open(content, 'w') as f:
- f.write("Some content")
-
- dist = Distribution()
- dist.dist_files = [('sdist', '3.7.0', content)]
-
- cmd = upload(dist)
- cmd.announce = mock.Mock()
- cmd.username = 'user'
- cmd.password = 'hunter2'
-
- yield Fix(cmd, urlopen)
-
-
-class TestUploadTest:
- def test_upload_metadata(self, patched_upload):
- cmd, patch = patched_upload
-
- # Set the metadata version to 2.1
- cmd.distribution.metadata.metadata_version = '2.1'
-
- # Run the command
- cmd.ensure_finalized()
- cmd.run()
-
- # Make sure we did the upload
- patch.assert_called_once()
-
- # Make sure the metadata version is correct in the headers
- entries = patched_upload.get_uploaded_metadata()
- assert entries['metadata_version'] == '2.1'
-
- def test_warns_deprecation(self):
- dist = Distribution()
- dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())]
-
- cmd = upload(dist)
- cmd.upload_file = mock.Mock()
- cmd.announce = mock.Mock()
-
- cmd.run()
+import pytest
- cmd.announce.assert_called_once_with(
- "WARNING: Uploading via this command is deprecated, use twine to "
- "upload instead (https://pypi.org/p/twine/)",
- log.WARN
- )
- def test_warns_deprecation_when_raising(self):
+class TestUpload:
+ def test_upload_exception(self):
+ """Ensure that the register command has been properly removed."""
dist = Distribution()
dist.dist_files = [(mock.Mock(), mock.Mock(), mock.Mock())]
cmd = upload(dist)
- cmd.upload_file = mock.Mock()
- cmd.upload_file.side_effect = Exception
- cmd.announce = mock.Mock()
-
- with pytest.raises(Exception):
- cmd.run()
-
- cmd.announce.assert_called_once_with(
- "WARNING: Uploading via this command is deprecated, use twine to "
- "upload instead (https://pypi.org/p/twine/)",
- log.WARN
- )
-
- @pytest.mark.parametrize('url', [
- 'https://example.com/a;parameter', # Has parameters
- 'https://example.com/a?query', # Has query
- 'https://example.com/a#fragment', # Has fragment
- 'ftp://example.com', # Invalid scheme
-
- ])
- def test_upload_file_invalid_url(self, url, patched_upload):
- patched_upload.urlopen.side_effect = Exception("Should not be reached")
-
- cmd = patched_upload.cmd
- cmd.repository = url
-
- cmd.ensure_finalized()
- with pytest.raises(AssertionError):
- cmd.run()
-
- def test_upload_file_http_error(self, patched_upload):
- patched_upload.urlopen.side_effect = six.moves.urllib.error.HTTPError(
- 'https://example.com',
- 404,
- 'File not found',
- None,
- None
- )
-
- cmd = patched_upload.cmd
- cmd.ensure_finalized()
- with pytest.raises(DistutilsError):
+ with pytest.raises(RemovedCommandError):
cmd.run()
-
- cmd.announce.assert_any_call(
- 'Upload failed (404): File not found',
- log.ERROR)
-
- def test_upload_file_os_error(self, patched_upload):
- patched_upload.urlopen.side_effect = OSError("Invalid")
-
- cmd = patched_upload.cmd
- cmd.ensure_finalized()
-
- with pytest.raises(OSError):
- cmd.run()
-
- cmd.announce.assert_any_call('Invalid', log.ERROR)
-
- @mock.patch('setuptools.command.upload.spawn')
- def test_upload_file_gpg(self, spawn, patched_upload):
- cmd, urlopen = patched_upload
-
- cmd.sign = True
- cmd.identity = "Alice"
- cmd.dry_run = True
- content_fname = cmd.distribution.dist_files[0][2]
- signed_file = content_fname + '.asc'
-
- with open(signed_file, 'wb') as f:
- f.write("signed-data".encode('utf-8'))
-
- cmd.ensure_finalized()
- cmd.run()
-
- # Make sure that GPG was called
- spawn.assert_called_once_with([
- "gpg", "--detach-sign", "--local-user", "Alice", "-a",
- content_fname
- ], dry_run=True)
-
- # Read the 'signed' data that was transmitted
- entries = patched_upload.get_uploaded_metadata()
- assert entries['gpg_signature'] == 'signed-data'
-
- def test_show_response_no_error(self, patched_upload):
- # This test is just that show_response doesn't throw an error
- # It is not really important what the printed response looks like
- # in a deprecated command, but we don't want to introduce new
- # errors when importing this function from distutils
-
- patched_upload.cmd.show_response = True
- patched_upload.cmd.ensure_finalized()
- patched_upload.cmd.run()
diff --git a/setuptools/tests/test_virtualenv.py b/setuptools/tests/test_virtualenv.py
index 7b5fea17..6549a6c0 100644
--- a/setuptools/tests/test_virtualenv.py
+++ b/setuptools/tests/test_virtualenv.py
@@ -1,4 +1,3 @@
-import distutils.command
import glob
import os
import sys
@@ -14,6 +13,17 @@ from .test_easy_install import make_nspkg_sdist
@pytest.fixture(autouse=True)
+def disable_requires_python(monkeypatch):
+ """
+ Disable Requires-Python on Python 2.7
+ """
+ if sys.version_info > (3,):
+ return
+
+ monkeypatch.setenv('PIP_IGNORE_REQUIRES_PYTHON', 'true')
+
+
+@pytest.fixture(autouse=True)
def pytest_virtualenv_works(virtualenv):
"""
pytest_virtualenv may not work. if it doesn't, skip these
@@ -53,10 +63,55 @@ def test_clean_env_install(bare_virtualenv):
)).format(source=SOURCE_DIR))
-def test_pip_upgrade_from_source(virtualenv):
+def _get_pip_versions():
+ # This fixture will attempt to detect if tests are being run without
+ # network connectivity and if so skip some tests
+
+ network = True
+ if not os.environ.get('NETWORK_REQUIRED', False): # pragma: nocover
+ try:
+ from urllib.request import urlopen
+ from urllib.error import URLError
+ except ImportError:
+ from urllib2 import urlopen, URLError # Python 2.7 compat
+
+ try:
+ urlopen('https://pypi.org', timeout=1)
+ except URLError:
+ # No network, disable most of these tests
+ network = False
+
+ network_versions = [
+ 'pip==9.0.3',
+ 'pip==10.0.1',
+ 'pip==18.1',
+ 'pip==19.0.1',
+ 'https://github.com/pypa/pip/archive/master.zip',
+ ]
+
+ versions = [None] + [
+ pytest.param(v, **({} if network else {'marks': pytest.mark.skip}))
+ for v in network_versions
+ ]
+
+ return versions
+
+
+@pytest.mark.parametrize('pip_version', _get_pip_versions())
+def test_pip_upgrade_from_source(pip_version, virtualenv):
"""
Check pip can upgrade setuptools from source.
"""
+ # Install pip/wheel, and remove setuptools (as it
+ # should not be needed for bootstraping from source)
+ if pip_version is None:
+ upgrade_pip = ()
+ else:
+ upgrade_pip = ('python -m pip install -U {pip_version} --retries=1',)
+ virtualenv.run(' && '.join((
+ 'pip uninstall -y setuptools',
+ 'pip install -U wheel',
+ ) + upgrade_pip).format(pip_version=pip_version))
dist_dir = virtualenv.workspace
# Generate source distribution / wheel.
virtualenv.run(' && '.join((
@@ -72,14 +127,12 @@ def test_pip_upgrade_from_source(virtualenv):
virtualenv.run('pip install --no-cache-dir --upgrade ' + sdist)
-def test_test_command_install_requirements(bare_virtualenv, tmpdir):
+def _check_test_command_install_requirements(virtualenv, tmpdir):
"""
Check the test command will install all required dependencies.
"""
- bare_virtualenv.run(' && '.join((
- 'cd {source}',
- 'python setup.py develop',
- )).format(source=SOURCE_DIR))
+ # Install setuptools.
+ virtualenv.run('python setup.py develop', cd=SOURCE_DIR)
def sdist(distname, version):
dist_path = tmpdir.join('%s-%s.tar.gz' % (distname, version))
@@ -130,18 +183,30 @@ def test_test_command_install_requirements(bare_virtualenv, tmpdir):
open('success', 'w').close()
'''))
# Run test command for test package.
- bare_virtualenv.run(' && '.join((
+ virtualenv.run(' && '.join((
'cd {tmpdir}',
'python setup.py test -s test',
)).format(tmpdir=tmpdir))
assert tmpdir.join('success').check()
+def test_test_command_install_requirements(virtualenv, tmpdir):
+ # Ensure pip/wheel packages are installed.
+ virtualenv.run(
+ "python -c \"__import__('pkg_resources').require(['pip', 'wheel'])\"")
+ _check_test_command_install_requirements(virtualenv, tmpdir)
+
+
+def test_test_command_install_requirements_when_using_easy_install(
+ bare_virtualenv, tmpdir):
+ _check_test_command_install_requirements(bare_virtualenv, tmpdir)
+
+
def test_no_missing_dependencies(bare_virtualenv):
"""
Quick and dirty test to ensure all external dependencies are vendored.
"""
- for command in ('upload',):#sorted(distutils.command.__all__):
+ for command in ('upload',): # sorted(distutils.command.__all__):
bare_virtualenv.run(' && '.join((
'cd {source}',
'python setup.py {command} -h',
diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py
index 6db5fa11..f72ccbbf 100644
--- a/setuptools/tests/test_wheel.py
+++ b/setuptools/tests/test_wheel.py
@@ -18,6 +18,7 @@ import pytest
from pkg_resources import Distribution, PathMetadata, PY_MAJOR
from setuptools.extern.packaging.utils import canonicalize_name
+from setuptools.extern.packaging.tags import parse_tag
from setuptools.wheel import Wheel
from .contexts import tempdir
@@ -63,6 +64,7 @@ WHEEL_INFO_TESTS = (
}),
)
+
@pytest.mark.parametrize(
('filename', 'info'), WHEEL_INFO_TESTS,
ids=[t[0] for t in WHEEL_INFO_TESTS]
@@ -123,11 +125,12 @@ def flatten_tree(tree):
def format_install_tree(tree):
- return {x.format(
- py_version=PY_MAJOR,
- platform=get_platform(),
- shlib_ext=get_config_var('EXT_SUFFIX') or get_config_var('SO'))
- for x in tree}
+ return {
+ x.format(
+ py_version=PY_MAJOR,
+ platform=get_platform(),
+ shlib_ext=get_config_var('EXT_SUFFIX') or get_config_var('SO'))
+ for x in tree}
def _check_wheel_install(filename, install_dir, install_tree_includes,
@@ -450,6 +453,35 @@ WHEEL_INSTALL_TESTS = (
),
dict(
+ id='empty_namespace_package',
+ file_defs={
+ 'foobar': {
+ '__init__.py':
+ "__import__('pkg_resources').declare_namespace(__name__)",
+ },
+ },
+ setup_kwargs=dict(
+ namespace_packages=['foobar'],
+ packages=['foobar'],
+ ),
+ install_tree=flatten_tree({
+ 'foo-1.0-py{py_version}.egg': [
+ 'foo-1.0-py{py_version}-nspkg.pth',
+ {'EGG-INFO': [
+ 'PKG-INFO',
+ 'RECORD',
+ 'WHEEL',
+ 'namespace_packages.txt',
+ 'top_level.txt',
+ ]},
+ {'foobar': [
+ '__init__.py',
+ ]},
+ ]
+ }),
+ ),
+
+ dict(
id='data_in_package',
file_defs={
'foo': {
@@ -487,6 +519,7 @@ WHEEL_INSTALL_TESTS = (
)
+
@pytest.mark.parametrize(
'params', WHEEL_INSTALL_TESTS,
ids=list(params['id'] for params in WHEEL_INSTALL_TESTS),
@@ -541,3 +574,12 @@ def test_wheel_no_dist_dir():
_check_wheel_install(wheel_path, install_dir, None,
project_name,
version, None)
+
+
+def test_wheel_is_compatible(monkeypatch):
+ def sys_tags():
+ for t in parse_tag('cp36-cp36m-manylinux1_x86_64'):
+ yield t
+ monkeypatch.setattr('setuptools.wheel.sys_tags', sys_tags)
+ assert Wheel(
+ 'onnxruntime-0.1.2-cp36-cp36m-manylinux1_x86_64.whl').is_compatible()
diff --git a/setuptools/tests/test_windows_wrappers.py b/setuptools/tests/test_windows_wrappers.py
index d2871c0f..2553394a 100644
--- a/setuptools/tests/test_windows_wrappers.py
+++ b/setuptools/tests/test_windows_wrappers.py
@@ -97,7 +97,8 @@ class TestCLI(WrapperTester):
'arg 4\\',
'arg5 a\\\\b',
]
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
+ proc = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
stdout, stderr = proc.communicate('hello\nworld\n'.encode('ascii'))
actual = stdout.decode('ascii').replace('\r\n', '\n')
expected = textwrap.dedent(r"""
@@ -134,7 +135,11 @@ class TestCLI(WrapperTester):
with (tmpdir / 'foo-script.py').open('w') as f:
f.write(self.prep_script(tmpl))
cmd = [str(tmpdir / 'foo.exe')]
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
+ proc = subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
stdout, stderr = proc.communicate()
actual = stdout.decode('ascii').replace('\r\n', '\n')
expected = textwrap.dedent(r"""
@@ -172,7 +177,9 @@ class TestGUI(WrapperTester):
str(tmpdir / 'test_output.txt'),
'Test Argument',
]
- proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
+ proc = subprocess.Popen(
+ cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
stdout, stderr = proc.communicate()
assert not stdout
assert not stderr