aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/tests
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/tests')
-rw-r--r--setuptools/tests/__init__.py4
-rw-r--r--setuptools/tests/files.py6
-rw-r--r--setuptools/tests/mod_with_constant.py1
-rw-r--r--setuptools/tests/test_bdist_egg.py2
-rw-r--r--setuptools/tests/test_build_clib.py59
-rw-r--r--setuptools/tests/test_config.py136
-rw-r--r--setuptools/tests/test_dep_util.py30
-rw-r--r--setuptools/tests/test_depends.py16
-rw-r--r--setuptools/tests/test_develop.py75
-rw-r--r--setuptools/tests/test_dist.py46
-rw-r--r--setuptools/tests/test_easy_install.py25
-rw-r--r--setuptools/tests/test_egg_info.py285
-rw-r--r--setuptools/tests/test_integration.py65
-rw-r--r--setuptools/tests/test_manifest.py128
-rw-r--r--setuptools/tests/test_msvc.py5
-rw-r--r--setuptools/tests/test_namespaces.py63
-rw-r--r--setuptools/tests/test_packageindex.py42
-rw-r--r--setuptools/tests/test_sandbox.py13
-rw-r--r--setuptools/tests/test_upload_docs.py2
-rw-r--r--setuptools/tests/test_virtualenv.py116
20 files changed, 987 insertions, 132 deletions
diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py
index dbf16201..8ae4402d 100644
--- a/setuptools/tests/__init__.py
+++ b/setuptools/tests/__init__.py
@@ -1,4 +1,5 @@
"""Tests for the 'setuptools' package"""
+import locale
import sys
import os
import distutils.core
@@ -16,8 +17,7 @@ import setuptools.depends as dep
from setuptools import Feature
from setuptools.depends import Require
-c_type = os.environ.get("LC_CTYPE", os.environ.get("LC_ALL"))
-is_ascii = c_type in ("C", "POSIX")
+is_ascii = locale.getpreferredencoding() == 'ANSI_X3.4-1968'
fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale")
diff --git a/setuptools/tests/files.py b/setuptools/tests/files.py
index 4364241b..98de9fc3 100644
--- a/setuptools/tests/files.py
+++ b/setuptools/tests/files.py
@@ -1,6 +1,9 @@
import os
+import pkg_resources.py31compat
+
+
def build_files(file_defs, prefix=""):
"""
Build a set of files/directories, as described by the file_defs dictionary.
@@ -24,8 +27,7 @@ def build_files(file_defs, prefix=""):
for name, contents in file_defs.items():
full_name = os.path.join(prefix, name)
if isinstance(contents, dict):
- if not os.path.exists(full_name):
- os.makedirs(full_name)
+ pkg_resources.py31compat.makedirs(full_name, exist_ok=True)
build_files(contents, prefix=full_name)
else:
with open(full_name, 'w') as f:
diff --git a/setuptools/tests/mod_with_constant.py b/setuptools/tests/mod_with_constant.py
new file mode 100644
index 00000000..ef755dd1
--- /dev/null
+++ b/setuptools/tests/mod_with_constant.py
@@ -0,0 +1 @@
+value = 'three, sir!'
diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py
index 5aabf404..d24aa366 100644
--- a/setuptools/tests/test_bdist_egg.py
+++ b/setuptools/tests/test_bdist_egg.py
@@ -41,4 +41,4 @@ class Test:
# let's see if we got our egg link at the right place
[content] = os.listdir('dist')
- assert re.match('foo-0.0.0-py[23].\d.egg$', content)
+ assert re.match(r'foo-0.0.0-py[23].\d.egg$', content)
diff --git a/setuptools/tests/test_build_clib.py b/setuptools/tests/test_build_clib.py
new file mode 100644
index 00000000..aebcc350
--- /dev/null
+++ b/setuptools/tests/test_build_clib.py
@@ -0,0 +1,59 @@
+import pytest
+import os
+import shutil
+
+import mock
+from distutils.errors import DistutilsSetupError
+from setuptools.command.build_clib import build_clib
+from setuptools.dist import Distribution
+
+
+class TestBuildCLib:
+ @mock.patch(
+ 'setuptools.command.build_clib.newer_pairwise_group'
+ )
+ def test_build_libraries(self, mock_newer):
+ dist = Distribution()
+ cmd = build_clib(dist)
+
+ # this will be a long section, just making sure all
+ # exceptions are properly raised
+ libs = [('example', {'sources': 'broken.c'})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.build_libraries(libs)
+
+ obj_deps = 'some_string'
+ libs = [('example', {'sources': ['source.c'], 'obj_deps': obj_deps})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.build_libraries(libs)
+
+ obj_deps = {'': ''}
+ libs = [('example', {'sources': ['source.c'], 'obj_deps': obj_deps})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.build_libraries(libs)
+
+ obj_deps = {'source.c': ''}
+ libs = [('example', {'sources': ['source.c'], 'obj_deps': obj_deps})]
+ with pytest.raises(DistutilsSetupError):
+ cmd.build_libraries(libs)
+
+ # 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 = ([],[])
+
+ obj_deps = {'': ('global.h',), 'example.c': ('example.h',)}
+ 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 not cmd.compiler.compile.called
+ assert cmd.compiler.create_static_lib.call_count == 1
+
+ # reset the call numbers so we can test again
+ cmd.compiler.reset_mock()
+
+ mock_newer.return_value = '' # anything as long as it's not ([],[])
+ cmd.build_libraries(libs)
+ assert cmd.compiler.compile.call_count == 1
+ assert cmd.compiler.create_static_lib.call_count == 1
diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py
index 21487720..cdfa5af4 100644
--- a/setuptools/tests/test_config.py
+++ b/setuptools/tests/test_config.py
@@ -9,6 +9,13 @@ class ErrConfigHandler(ConfigHandler):
"""Erroneous handler. Fails to implement required methods."""
+def make_package_dir(name, base_dir):
+ dir_package = base_dir.mkdir(name)
+ init_file = dir_package.join('__init__.py')
+ init_file.write('')
+ return dir_package, init_file
+
+
def fake_env(tmpdir, setup_cfg, setup_py=None):
if setup_py is None:
@@ -18,11 +25,12 @@ def fake_env(tmpdir, setup_cfg, setup_py=None):
)
tmpdir.join('setup.py').write(setup_py)
- tmpdir.join('setup.cfg').write(setup_cfg)
+ config = tmpdir.join('setup.cfg')
+ config.write(setup_cfg)
- package_name = 'fake_package'
- dir_package = tmpdir.mkdir(package_name)
- dir_package.join('__init__.py').write(
+ package_dir, init_file = make_package_dir('fake_package', tmpdir)
+
+ init_file.write(
'VERSION = (1, 2, 3)\n'
'\n'
'VERSION_MAJOR = 1'
@@ -31,6 +39,7 @@ def fake_env(tmpdir, setup_cfg, setup_py=None):
' return [3, 4, 5, "dev"]\n'
'\n'
)
+ return package_dir, config
@contextlib.contextmanager
@@ -55,7 +64,7 @@ def test_parsers_implemented():
class TestConfigurationReader:
def test_basic(self, tmpdir):
- fake_env(
+ _, config = fake_env(
tmpdir,
'[metadata]\n'
'version = 10.1.1\n'
@@ -64,7 +73,7 @@ class TestConfigurationReader:
'[options]\n'
'scripts = bin/a.py, bin/b.py\n'
)
- config_dict = read_configuration('%s' % tmpdir.join('setup.cfg'))
+ config_dict = read_configuration('%s' % config)
assert config_dict['metadata']['version'] == '10.1.1'
assert config_dict['metadata']['keywords'] == ['one', 'two']
assert config_dict['options']['scripts'] == ['bin/a.py', 'bin/b.py']
@@ -73,6 +82,24 @@ class TestConfigurationReader:
with pytest.raises(DistutilsFileError):
read_configuration('%s' % tmpdir.join('setup.cfg'))
+ def test_ignore_errors(self, tmpdir):
+ _, config = fake_env(
+ tmpdir,
+ '[metadata]\n'
+ 'version = attr: none.VERSION\n'
+ 'keywords = one, two\n'
+ )
+ with pytest.raises(ImportError):
+ read_configuration('%s' % config)
+
+ config_dict = read_configuration(
+ '%s' % config, ignore_option_errors=True)
+
+ assert config_dict['metadata']['keywords'] == ['one', 'two']
+ assert 'version' not in config_dict['metadata']
+
+ config.remove()
+
class TestMetadata:
@@ -112,6 +139,24 @@ class TestMetadata:
assert metadata.download_url == 'http://test.test.com/test/'
assert metadata.maintainer_email == 'test@test.com'
+ def test_file_mixed(self, tmpdir):
+
+ fake_env(
+ tmpdir,
+ '[metadata]\n'
+ 'long_description = file: README.rst, CHANGES.rst\n'
+ '\n'
+ )
+
+ tmpdir.join('README.rst').write('readme contents\nline2')
+ tmpdir.join('CHANGES.rst').write('changelog contents\nand stuff')
+
+ with get_dist(tmpdir) as dist:
+ assert dist.metadata.long_description == (
+ 'readme contents\nline2\n'
+ 'changelog contents\nand stuff'
+ )
+
def test_file_sandboxed(self, tmpdir):
fake_env(
@@ -172,7 +217,7 @@ class TestMetadata:
def test_version(self, tmpdir):
- fake_env(
+ _, config = fake_env(
tmpdir,
'[metadata]\n'
'version = attr: fake_package.VERSION\n'
@@ -180,14 +225,14 @@ class TestMetadata:
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
- tmpdir.join('setup.cfg').write(
+ config.write(
'[metadata]\n'
'version = attr: fake_package.get_version\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '3.4.5.dev'
- tmpdir.join('setup.cfg').write(
+ config.write(
'[metadata]\n'
'version = attr: fake_package.VERSION_MAJOR\n'
)
@@ -198,7 +243,7 @@ class TestMetadata:
subpack.join('__init__.py').write('')
subpack.join('submodule.py').write('VERSION = (2016, 11, 26)')
- tmpdir.join('setup.cfg').write(
+ config.write(
'[metadata]\n'
'version = attr: fake_package.subpackage.submodule.VERSION\n'
)
@@ -230,11 +275,12 @@ class TestMetadata:
def test_classifiers(self, tmpdir):
expected = set([
'Framework :: Django',
+ 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
])
# From file.
- fake_env(
+ _, config = fake_env(
tmpdir,
'[metadata]\n'
'classifiers = file: classifiers\n'
@@ -242,19 +288,21 @@ class TestMetadata:
tmpdir.join('classifiers').write(
'Framework :: Django\n'
+ 'Programming Language :: Python :: 3\n'
'Programming Language :: Python :: 3.5\n'
)
with get_dist(tmpdir) as dist:
assert set(dist.metadata.classifiers) == expected
- # From section.
- tmpdir.join('setup.cfg').write(
- '[metadata.classifiers]\n'
- 'Framework :: Django\n'
- 'Programming Language :: Python :: 3.5\n'
+ # From list notation
+ config.write(
+ '[metadata]\n'
+ 'classifiers =\n'
+ ' Framework :: Django\n'
+ ' Programming Language :: Python :: 3\n'
+ ' Programming Language :: Python :: 3.5\n'
)
-
with get_dist(tmpdir) as dist:
assert set(dist.metadata.classifiers) == expected
@@ -282,6 +330,8 @@ class TestOptions:
'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'
+ 'python_requires = >=1.0, !=2.8\n'
+ 'py_modules = module1, module2\n'
)
with get_dist(tmpdir) as dist:
assert dist.zip_safe
@@ -301,7 +351,7 @@ class TestOptions:
])
assert dist.install_requires == ([
'docutils>=0.3',
- 'pack ==1.1, ==1.3',
+ 'pack==1.1,==1.3',
'hey'
])
assert dist.setup_requires == ([
@@ -310,6 +360,8 @@ class TestOptions:
'there'
])
assert dist.tests_require == ['mock==0.7.2', 'pytest']
+ assert dist.python_requires == '>=1.0, !=2.8'
+ assert dist.py_modules == ['module1', 'module2']
def test_multiline(self, tmpdir):
fake_env(
@@ -369,7 +421,7 @@ class TestOptions:
])
assert dist.install_requires == ([
'docutils>=0.3',
- 'pack ==1.1, ==1.3',
+ 'pack==1.1,==1.3',
'hey'
])
assert dist.setup_requires == ([
@@ -421,6 +473,46 @@ class TestOptions:
with get_dist(tmpdir) as dist:
assert dist.packages == ['fake_package']
+ def test_find_directive(self, tmpdir):
+ dir_package, config = fake_env(
+ tmpdir,
+ '[options]\n'
+ 'packages = find:\n'
+ )
+
+ dir_sub_one, _ = make_package_dir('sub_one', dir_package)
+ dir_sub_two, _ = make_package_dir('sub_two', dir_package)
+
+ with get_dist(tmpdir) as dist:
+ assert set(dist.packages) == set([
+ 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one'
+ ])
+
+ config.write(
+ '[options]\n'
+ 'packages = find:\n'
+ '\n'
+ '[options.packages.find]\n'
+ 'where = .\n'
+ 'include =\n'
+ ' fake_package.sub_one\n'
+ ' two\n'
+ )
+ with get_dist(tmpdir) as dist:
+ assert dist.packages == ['fake_package.sub_one']
+
+ config.write(
+ '[options]\n'
+ 'packages = find:\n'
+ '\n'
+ '[options.packages.find]\n'
+ 'exclude =\n'
+ ' fake_package.sub_one\n'
+ )
+ with get_dist(tmpdir) as dist:
+ assert set(dist.packages) == set(
+ ['fake_package', 'fake_package.sub_two'])
+
def test_extras_require(self, tmpdir):
fake_env(
tmpdir,
@@ -434,11 +526,11 @@ class TestOptions:
with get_dist(tmpdir) as dist:
assert dist.extras_require == {
'pdf': ['ReportLab>=1.2', 'RXP'],
- 'rest': ['docutils>=0.3', 'pack ==1.1, ==1.3']
+ 'rest': ['docutils>=0.3', 'pack==1.1,==1.3']
}
def test_entry_points(self, tmpdir):
- fake_env(
+ _, config = fake_env(
tmpdir,
'[options.entry_points]\n'
'group1 = point1 = pack.module:func, '
@@ -463,7 +555,7 @@ class TestOptions:
tmpdir.join('entry_points').write(expected)
# From file.
- tmpdir.join('setup.cfg').write(
+ config.write(
'[options]\n'
'entry_points = file: entry_points\n'
)
diff --git a/setuptools/tests/test_dep_util.py b/setuptools/tests/test_dep_util.py
new file mode 100644
index 00000000..e5027c10
--- /dev/null
+++ b/setuptools/tests/test_dep_util.py
@@ -0,0 +1,30 @@
+from setuptools.dep_util import newer_pairwise_group
+import os
+import pytest
+
+
+@pytest.fixture
+def groups_target(tmpdir):
+ """Sets up some older sources, a target and newer sources.
+ Returns a 3-tuple in this order.
+ """
+ creation_order = ['older.c', 'older.h', 'target.o', 'newer.c', 'newer.h']
+ mtime = 0
+
+ for i in range(len(creation_order)):
+ creation_order[i] = os.path.join(str(tmpdir), creation_order[i])
+ with open(creation_order[i], 'w'):
+ pass
+
+ # make sure modification times are sequential
+ os.utime(creation_order[i], (mtime, mtime))
+ mtime += 1
+
+ return creation_order[:2], creation_order[2], creation_order[3:]
+
+
+def test_newer_pairwise_group(groups_target):
+ older = newer_pairwise_group([groups_target[0]], [groups_target[1]])
+ newer = newer_pairwise_group([groups_target[2]], [groups_target[1]])
+ assert older == ([], [])
+ assert newer == ([groups_target[2]], [groups_target[1]])
diff --git a/setuptools/tests/test_depends.py b/setuptools/tests/test_depends.py
new file mode 100644
index 00000000..e0cfa880
--- /dev/null
+++ b/setuptools/tests/test_depends.py
@@ -0,0 +1,16 @@
+import sys
+
+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
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index 4cf483f2..ad7cfa05 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -1,17 +1,23 @@
"""develop tests
"""
+
+from __future__ import absolute_import, unicode_literals
+
import os
import site
import sys
import io
+import subprocess
from setuptools.extern import six
+from setuptools.command import test
import pytest
from setuptools.command.develop import develop
from setuptools.dist import Distribution
from . import contexts
+from . import namespaces
SETUP_PY = """\
from setuptools import setup
@@ -114,3 +120,72 @@ class TestDevelop:
cmd.install_dir = tmpdir
cmd.run()
# assert '0.0' not in foocmd_text
+
+
+class TestResolver:
+ """
+ TODO: These tests were written with a minimal understanding
+ of what _resolve_setup_path is intending to do. Come up with
+ more meaningful cases that look like real-world scenarios.
+ """
+ def test_resolve_setup_path_cwd(self):
+ assert develop._resolve_setup_path('.', '.', '.') == '.'
+
+ def test_resolve_setup_path_one_dir(self):
+ assert develop._resolve_setup_path('pkgs', '.', 'pkgs') == '../'
+
+ def test_resolve_setup_path_one_dir_trailing_slash(self):
+ assert develop._resolve_setup_path('pkgs/', '.', 'pkgs') == '../'
+
+
+class TestNamespaces:
+
+ @staticmethod
+ def install_develop(src_dir, target):
+
+ develop_cmd = [
+ sys.executable,
+ 'setup.py',
+ 'develop',
+ '--install-dir', str(target),
+ ]
+ with src_dir.as_cwd():
+ with test.test.paths_on_pythonpath([str(target)]):
+ subprocess.check_call(develop_cmd)
+
+ @pytest.mark.skipif(bool(os.environ.get("APPVEYOR")),
+ reason="https://github.com/pypa/setuptools/issues/851")
+ def test_namespace_package_importable(self, tmpdir):
+ """
+ Installing two packages sharing the same namespace, one installed
+ naturally using pip or `--single-version-externally-managed`
+ and the other installed using `develop` should leave the namespace
+ in tact and both packages reachable by import.
+ """
+ pkg_A = namespaces.build_namespace_package(tmpdir, 'myns.pkgA')
+ pkg_B = namespaces.build_namespace_package(tmpdir, 'myns.pkgB')
+ target = tmpdir / 'packages'
+ # use pip to install to the target directory
+ install_cmd = [
+ 'pip',
+ 'install',
+ str(pkg_A),
+ '-t', str(target),
+ ]
+ subprocess.check_call(install_cmd)
+ self.install_develop(pkg_B, target)
+ namespaces.make_site_dir(target)
+ try_import = [
+ sys.executable,
+ '-c', 'import myns.pkgA; import myns.pkgB',
+ ]
+ with test.test.paths_on_pythonpath([str(target)]):
+ subprocess.check_call(try_import)
+
+ # additionally ensure that pkg_resources import works
+ pkg_resources_imp = [
+ sys.executable,
+ '-c', 'import pkg_resources',
+ ]
+ with test.test.paths_on_pythonpath([str(target)]):
+ subprocess.check_call(pkg_resources_imp)
diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py
new file mode 100644
index 00000000..435ffec0
--- /dev/null
+++ b/setuptools/tests/test_dist.py
@@ -0,0 +1,46 @@
+from setuptools import Distribution
+from setuptools.extern.six.moves.urllib.request import pathname2url
+from setuptools.extern.six.moves.urllib_parse import urljoin
+
+from .textwrap import DALS
+from .test_easy_install import make_nspkg_sdist
+
+
+def test_dist_fetch_build_egg(tmpdir):
+ """
+ Check multiple calls to `Distribution.fetch_build_egg` work as expected.
+ """
+ index = tmpdir.mkdir('index')
+ index_url = urljoin('file://', pathname2url(str(index)))
+ def sdist_with_index(distname, version):
+ dist_dir = index.mkdir(distname)
+ dist_sdist = '%s-%s.tar.gz' % (distname, version)
+ make_nspkg_sdist(str(dist_dir.join(dist_sdist)), distname, version)
+ with dist_dir.join('index.html').open('w') as fp:
+ fp.write(DALS(
+ '''
+ <!DOCTYPE html><html><body>
+ <a href="{dist_sdist}" rel="internal">{dist_sdist}</a><br/>
+ </body></html>
+ '''
+ ).format(dist_sdist=dist_sdist))
+ sdist_with_index('barbazquux', '3.2.0')
+ sdist_with_index('barbazquux-runner', '2.11.1')
+ with tmpdir.join('setup.cfg').open('w') as fp:
+ fp.write(DALS(
+ '''
+ [easy_install]
+ index_url = {index_url}
+ '''
+ ).format(index_url=index_url))
+ reqs = '''
+ barbazquux-runner
+ barbazquux
+ '''.split()
+ with tmpdir.as_cwd():
+ dist = Distribution()
+ resolved_dists = [
+ dist.fetch_build_egg(r)
+ for r in reqs
+ ]
+ assert [dist.key for dist in resolved_dists if dist] == reqs
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index 6f9bc8e1..e4ed556f 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -14,15 +14,12 @@ import itertools
import distutils.errors
import io
import zipfile
+import mock
import time
from setuptools.extern.six.moves import urllib
import pytest
-try:
- from unittest import mock
-except ImportError:
- import mock
from setuptools import sandbox
from setuptools.sandbox import run_setup
@@ -33,6 +30,7 @@ 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 import fail_on_ascii
import pkg_resources
from . import contexts
@@ -67,7 +65,7 @@ class TestEasyInstallTest:
def test_get_script_args(self):
header = ei.CommandSpec.best().from_environment().as_header()
- expected = header + DALS("""
+ expected = header + DALS(r"""
# EASY-INSTALL-ENTRY-SCRIPT: 'spec','console_scripts','name'
__requires__ = 'spec'
import re
@@ -168,10 +166,7 @@ class TestEasyInstallTest:
sdist_zip.close()
return str(sdist)
- @pytest.mark.xfail(reason="#709 and #710")
- # also
- #@pytest.mark.xfail(setuptools.tests.is_ascii,
- # reason="https://github.com/pypa/setuptools/issues/706")
+ @fail_on_ascii
def test_unicode_filename_in_sdist(self, sdist_unicode, tmpdir, monkeypatch):
"""
The install command should execute correctly even if
@@ -571,18 +566,6 @@ def create_setup_requires_package(path, distname='foobar', version='0.1',
return test_pkg
-def make_trivial_sdist(dist_path, setup_py):
- """Create a simple sdist tarball at dist_path, containing just a
- setup.py, the contents of which are provided by the setup_py string.
- """
-
- setup_py_file = tarfile.TarInfo(name='setup.py')
- setup_py_bytes = io.BytesIO(setup_py.encode('utf-8'))
- setup_py_file.size = len(setup_py_bytes.getvalue())
- with tarfile.open(dist_path, 'w:gz') as dist:
- dist.addfile(setup_py_file, fileobj=setup_py_bytes)
-
-
@pytest.mark.skipif(
sys.platform.startswith('java') and ei.is_sh(sys.executable),
reason="Test cannot run under java when executable is sh"
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index 7bf6b68a..4c04d298 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -1,3 +1,5 @@
+import sys
+import ast
import os
import glob
import re
@@ -81,9 +83,8 @@ class TestEggInfo(object):
assert '[egg_info]' in content
assert 'tag_build =' in content
assert 'tag_date = 0' in content
- assert 'tag_svn_revision = 0' in content
- expected_order = 'tag_build', 'tag_date', 'tag_svn_revision'
+ expected_order = 'tag_build', 'tag_date',
self._validate_content_order(content, expected_order)
@@ -109,7 +110,6 @@ class TestEggInfo(object):
[egg_info]
tag_build =
tag_date = 0
- tag_svn_revision = 0
"""),
})
dist = Distribution()
@@ -123,9 +123,8 @@ class TestEggInfo(object):
assert '[egg_info]' in content
assert 'tag_build =' in content
assert 'tag_date = 0' in content
- assert 'tag_svn_revision = 0' in content
- expected_order = 'tag_build', 'tag_date', 'tag_svn_revision'
+ expected_order = 'tag_build', 'tag_date',
self._validate_content_order(content, expected_order)
@@ -160,48 +159,262 @@ class TestEggInfo(object):
sources_txt = os.path.join(egg_info_dir, 'SOURCES.txt')
assert 'docs/usage.rst' in open(sources_txt).read().split('\n')
- def _setup_script_with_requires(self, requires_line):
- setup_script = DALS("""
+ def _setup_script_with_requires(self, requires, use_setup_cfg=False):
+ setup_script = DALS(
+ '''
from setuptools import setup
- setup(
- name='foo',
- %s
- zip_safe=False,
- )
- """ % requires_line)
- build_files({
- 'setup.py': setup_script,
- })
+ setup(name='foo', zip_safe=False, %s)
+ '''
+ ) % ('' if use_setup_cfg else requires)
+ setup_config = requires if use_setup_cfg else ''
+ build_files({'setup.py': setup_script,
+ 'setup.cfg': setup_config})
+
+ mismatch_marker = "python_version<'{this_ver}'".format(
+ this_ver=sys.version_info[0],
+ )
+ # Alternate equivalent syntax.
+ mismatch_marker_alternate = 'python_version < "{this_ver}"'.format(
+ this_ver=sys.version_info[0],
+ )
+ invalid_marker = "<=>++"
+
+ class RequiresTestHelper(object):
+
+ @staticmethod
+ def parametrize(*test_list, **format_dict):
+ idlist = []
+ argvalues = []
+ for test in test_list:
+ test_params = test.lstrip().split('\n\n', 3)
+ name_kwargs = test_params.pop(0).split('\n')
+ if len(name_kwargs) > 1:
+ install_cmd_kwargs = ast.literal_eval(name_kwargs[1].strip())
+ else:
+ install_cmd_kwargs = {}
+ name = name_kwargs[0].strip()
+ setup_py_requires, setup_cfg_requires, expected_requires = (
+ DALS(a).format(**format_dict) for a in test_params
+ )
+ for id_, requires, use_cfg in (
+ (name, setup_py_requires, False),
+ (name + '_in_setup_cfg', setup_cfg_requires, True),
+ ):
+ idlist.append(id_)
+ marks = ()
+ if requires.startswith('@xfail\n'):
+ requires = requires[7:]
+ marks = pytest.mark.xfail
+ argvalues.append(pytest.param(requires, use_cfg,
+ expected_requires,
+ install_cmd_kwargs,
+ marks=marks))
+ return pytest.mark.parametrize('requires,use_setup_cfg,'
+ 'expected_requires,install_cmd_kwargs',
+ argvalues, ids=idlist)
+
+ @RequiresTestHelper.parametrize(
+ # Format of a test:
+ #
+ # id
+ # install_cmd_kwargs [optional]
+ #
+ # requires block (when used in setup.py)
+ #
+ # requires block (when used in setup.cfg)
+ #
+ # expected contents of requires.txt
+
+ '''
+ install_requires_with_marker
+
+ install_requires=["barbazquux;{mismatch_marker}"],
+
+ [options]
+ install_requires =
+ barbazquux; {mismatch_marker}
+
+ [:{mismatch_marker_alternate}]
+ barbazquux
+ ''',
+
+ '''
+ install_requires_with_extra
+ {'cmd': ['egg_info']}
+
+ install_requires=["barbazquux [test]"],
+
+ [options]
+ install_requires =
+ barbazquux [test]
+
+ barbazquux[test]
+ ''',
+
+ '''
+ install_requires_with_extra_and_marker
+
+ install_requires=["barbazquux [test]; {mismatch_marker}"],
+
+ [options]
+ install_requires =
+ barbazquux [test]; {mismatch_marker}
+
+ [:{mismatch_marker_alternate}]
+ barbazquux[test]
+ ''',
+
+ '''
+ setup_requires_with_markers
+
+ setup_requires=["barbazquux;{mismatch_marker}"],
+
+ [options]
+ setup_requires =
+ barbazquux; {mismatch_marker}
+
+ ''',
+
+ '''
+ tests_require_with_markers
+ {'cmd': ['test'], 'output': "Ran 0 tests in"}
+
+ tests_require=["barbazquux;{mismatch_marker}"],
+
+ [options]
+ tests_require =
+ barbazquux; {mismatch_marker}
+
+ ''',
+
+ '''
+ extras_require_with_extra
+ {'cmd': ['egg_info']}
- def test_install_requires_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """install_requires=["barbazquux;python_version<'2'"],""")
- self._run_install_command(tmpdir_cwd, env)
- egg_info_dir = self._find_egg_info_files(env.paths['lib']).base
+ extras_require={{"extra": ["barbazquux [test]"]}},
+
+ [options.extras_require]
+ extra = barbazquux [test]
+
+ [extra]
+ barbazquux[test]
+ ''',
+
+ '''
+ extras_require_with_extra_and_marker_in_req
+
+ extras_require={{"extra": ["barbazquux [test]; {mismatch_marker}"]}},
+
+ [options.extras_require]
+ extra =
+ barbazquux [test]; {mismatch_marker}
+
+ [extra]
+
+ [extra:{mismatch_marker_alternate}]
+ barbazquux[test]
+ ''',
+
+ # FIXME: ConfigParser does not allow : in key names!
+ '''
+ extras_require_with_marker
+
+ extras_require={{":{mismatch_marker}": ["barbazquux"]}},
+
+ @xfail
+ [options.extras_require]
+ :{mismatch_marker} = barbazquux
+
+ [:{mismatch_marker}]
+ barbazquux
+ ''',
+
+ '''
+ extras_require_with_marker_in_req
+
+ extras_require={{"extra": ["barbazquux; {mismatch_marker}"]}},
+
+ [options.extras_require]
+ extra =
+ barbazquux; {mismatch_marker}
+
+ [extra]
+
+ [extra:{mismatch_marker_alternate}]
+ barbazquux
+ ''',
+
+ '''
+ extras_require_with_empty_section
+
+ extras_require={{"empty": []}},
+
+ [options.extras_require]
+ empty =
+
+ [empty]
+ ''',
+ # Format arguments.
+ invalid_marker=invalid_marker,
+ mismatch_marker=mismatch_marker,
+ mismatch_marker_alternate=mismatch_marker_alternate,
+ )
+ def test_requires(self, tmpdir_cwd, env,
+ requires, use_setup_cfg,
+ expected_requires, install_cmd_kwargs):
+ self._setup_script_with_requires(requires, use_setup_cfg)
+ self._run_install_command(tmpdir_cwd, env, **install_cmd_kwargs)
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
requires_txt = os.path.join(egg_info_dir, 'requires.txt')
- assert "barbazquux;python_version<'2'" in open(
- requires_txt).read().split('\n')
+ if os.path.exists(requires_txt):
+ with open(requires_txt) as fp:
+ install_requires = fp.read()
+ else:
+ install_requires = ''
+ assert install_requires.lstrip() == expected_requires
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
- def test_setup_requires_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """setup_requires=["barbazquux;python_version<'2'"],""")
- self._run_install_command(tmpdir_cwd, env)
+ def test_extras_require_with_invalid_marker(self, tmpdir_cwd, env):
+ tmpl = 'extras_require={{":{marker}": ["barbazquux"]}},'
+ req = tmpl.format(marker=self.invalid_marker)
+ self._setup_script_with_requires(req)
+ with pytest.raises(AssertionError):
+ self._run_install_command(tmpdir_cwd, env)
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
- def test_tests_require_with_markers(self, tmpdir_cwd, env):
- self._setup_script_with_requires(
- """tests_require=["barbazquux;python_version<'2'"],""")
- self._run_install_command(
- tmpdir_cwd, env, cmd=['test'], output="Ran 0 tests in")
+ def test_extras_require_with_invalid_marker_in_req(self, tmpdir_cwd, env):
+ tmpl = 'extras_require={{"extra": ["barbazquux; {marker}"]}},'
+ req = tmpl.format(marker=self.invalid_marker)
+ self._setup_script_with_requires(req)
+ with pytest.raises(AssertionError):
+ self._run_install_command(tmpdir_cwd, env)
assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
- def test_extra_requires_with_markers(self, tmpdir_cwd, env):
+ 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`
+ # line to the `PKG-INFO` file in the `<distribution>.egg-info`
+ # directory.
+ # `Description-Content-Type` is described at
+ # https://github.com/pypa/python-packaging-user-guide/pull/258
+
self._setup_script_with_requires(
- """extra_requires={":python_version<'2'": ["barbazquux"]},""")
- self._run_install_command(tmpdir_cwd, env)
- assert glob.glob(os.path.join(env.paths['lib'], 'barbazquux*')) == []
+ """long_description_content_type='text/markdown',""")
+ environ = os.environ.copy().update(
+ HOME=env.paths['home'],
+ )
+ code, data = environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
+ data_stream=1,
+ env=environ,
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+ with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file:
+ pkg_info_lines = pkginfo_file.read().split('\n')
+ expected_line = 'Description-Content-Type: text/markdown'
+ assert expected_line in pkg_info_lines
def test_python_requires_egg_info(self, tmpdir_cwd, env):
self._setup_script_with_requires(
diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py
index 78fb0627..3a9a6c50 100644
--- a/setuptools/tests/test_integration.py
+++ b/setuptools/tests/test_integration.py
@@ -98,3 +98,68 @@ def test_pbr(install_context):
def test_python_novaclient(install_context):
_install_one('python-novaclient', install_context,
'novaclient', 'base.py')
+
+
+def test_pyuri(install_context):
+ """
+ Install the pyuri package (version 0.3.1 at the time of writing).
+
+ This is also a regression test for issue #1016.
+ """
+ _install_one('pyuri', install_context, 'pyuri', 'uri.py')
+
+ pyuri = install_context.installed_projects['pyuri']
+
+ # The package data should be installed.
+ 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']
+@pytest.mark.parametrize("build_dep", build_deps)
+@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
+ setuptools.
+ """
+ if 'pyparsing' in build_dep:
+ pytest.xfail(reason="Project imports setuptools unconditionally")
+ build_target = tmpdir_factory.mktemp('source')
+ build_dir = download_and_extract(request, build_dep, build_target)
+ install_target = tmpdir_factory.mktemp('target')
+ output = install(build_dir, install_target)
+ for line in output.splitlines():
+ match = re.search('Unknown distribution option: (.*)', line)
+ allowed_unknowns = [
+ 'test_suite',
+ 'tests_require',
+ 'install_requires',
+ ]
+ assert not match or match.group(1).strip('"\'') in allowed_unknowns
+
+
+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)
+ return output.decode('utf-8')
+
+
+def download_and_extract(request, req, target):
+ 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))
+ opener = zipfile.ZipFile if filename.endswith('.zip') else tarfile.open
+ with opener(filename) as archive:
+ archive.extractall(target)
+ return os.path.join(target, os.listdir(target)[0])
diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py
index 62b6d708..65eec7d9 100644
--- a/setuptools/tests/test_manifest.py
+++ b/setuptools/tests/test_manifest.py
@@ -6,9 +6,11 @@ import os
import shutil
import sys
import tempfile
+import itertools
from distutils import log
from distutils.errors import DistutilsTemplateError
+import pkg_resources.py31compat
from setuptools.command.egg_info import FileList, egg_info, translate_pattern
from setuptools.dist import Distribution
from setuptools.extern import six
@@ -65,32 +67,94 @@ default_files = frozenset(map(make_local_path, [
]))
-def get_pattern(glob):
- return translate_pattern(make_local_path(glob)).pattern
-
-
-def test_translated_pattern_test():
- l = make_local_path
- assert get_pattern('foo') == r'foo\Z(?ms)'
- assert get_pattern(l('foo/bar')) == l(r'foo\/bar\Z(?ms)')
+translate_specs = [
+ ('foo', ['foo'], ['bar', 'foobar']),
+ ('foo/bar', ['foo/bar'], ['foo/bar/baz', './foo/bar', 'foo']),
# Glob matching
- assert get_pattern('*.txt') == l(r'[^\/]*\.txt\Z(?ms)')
- assert get_pattern('dir/*.txt') == l(r'dir\/[^\/]*\.txt\Z(?ms)')
- assert get_pattern('*/*.py') == l(r'[^\/]*\/[^\/]*\.py\Z(?ms)')
- assert get_pattern('docs/page-?.txt') \
- == l(r'docs\/page\-[^\/]\.txt\Z(?ms)')
+ ('*.txt', ['foo.txt', 'bar.txt'], ['foo/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']),
# Globstars change what they mean depending upon where they are
- assert get_pattern(l('foo/**/bar')) == l(r'foo\/(?:[^\/]+\/)*bar\Z(?ms)')
- assert get_pattern(l('foo/**')) == l(r'foo\/.*\Z(?ms)')
- assert get_pattern(l('**')) == r'.*\Z(?ms)'
+ (
+ 'foo/**/bar',
+ ['foo/bing/bar', 'foo/bing/bang/bar', 'foo/bar'],
+ ['foo/abar'],
+ ),
+ (
+ 'foo/**',
+ ['foo/bar/bing.py', 'foo/x'],
+ ['/foo/x'],
+ ),
+ (
+ '**',
+ ['x', 'abc/xyz', '@nything'],
+ [],
+ ),
# Character classes
- assert get_pattern('pre[one]post') == r'pre[one]post\Z(?ms)'
- assert get_pattern('hello[!one]world') == r'hello[^one]world\Z(?ms)'
- assert get_pattern('[]one].txt') == r'[\]one]\.txt\Z(?ms)'
- assert get_pattern('foo[!]one]bar') == r'foo[^\]one]bar\Z(?ms)'
+ (
+ 'pre[one]post',
+ ['preopost', 'prenpost', 'preepost'],
+ ['prepost', 'preonepost'],
+ ),
+
+ (
+ 'hello[!one]world',
+ ['helloxworld', 'helloyworld'],
+ ['hellooworld', 'helloworld', 'hellooneworld'],
+ ),
+
+ (
+ '[]one].txt',
+ ['o.txt', '].txt', 'e.txt'],
+ ['one].txt'],
+ ),
+
+ (
+ 'foo[!]one]bar',
+ ['fooybar'],
+ ['foo]bar', 'fooobar', 'fooebar'],
+ ),
+
+]
+"""
+A spec of inputs for 'translate_pattern' and matches and mismatches
+for that input.
+"""
+
+match_params = itertools.chain.from_iterable(
+ zip(itertools.repeat(pattern), matches)
+ for pattern, matches, mismatches in translate_specs
+)
+
+
+@pytest.fixture(params=match_params)
+def pattern_match(request):
+ return map(make_local_path, request.param)
+
+
+mismatch_params = itertools.chain.from_iterable(
+ zip(itertools.repeat(pattern), mismatches)
+ for pattern, matches, mismatches in translate_specs
+)
+
+
+@pytest.fixture(params=mismatch_params)
+def pattern_mismatch(request):
+ return map(make_local_path, request.param)
+
+
+def test_translated_pattern_match(pattern_match):
+ pattern, target = pattern_match
+ assert translate_pattern(pattern).match(target)
+
+
+def test_translated_pattern_mismatch(pattern_mismatch):
+ pattern, target = pattern_mismatch
+ assert not translate_pattern(pattern).match(target)
class TempDirTestCase(object):
@@ -206,6 +270,15 @@ class TestManifestTest(TempDirTestCase):
l('app/static/app.css'), l('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
+ 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')])
+ assert files == self.get_files()
+
def test_graft_global_exclude(self):
"""Exclude all *.map files in the project."""
l = make_local_path
@@ -289,8 +362,7 @@ class TestFileListTest(TempDirTestCase):
for file in files:
file = os.path.join(self.temp_dir, file)
dirname, basename = os.path.split(file)
- if not os.path.exists(dirname):
- os.makedirs(dirname)
+ pkg_resources.py31compat.makedirs(dirname, exist_ok=True)
open(file, 'w').close()
def test_process_template_line(self):
@@ -449,11 +521,6 @@ class TestFileListTest(TempDirTestCase):
assert file_list.files == ['a.py', l('d/c.py')]
self.assertWarnings()
- file_list.process_template_line('global-include .txt')
- file_list.sort()
- assert file_list.files == ['a.py', 'b.txt', l('d/c.py')]
- self.assertNoWarnings()
-
def test_global_exclude(self):
l = make_local_path
# global-exclude
@@ -470,13 +537,6 @@ class TestFileListTest(TempDirTestCase):
assert file_list.files == ['b.txt']
self.assertWarnings()
- file_list = FileList()
- file_list.files = ['a.py', 'b.txt', l('d/c.pyc'), 'e.pyo']
- file_list.process_template_line('global-exclude .py[co]')
- file_list.sort()
- assert file_list.files == ['a.py', 'b.txt']
- self.assertNoWarnings()
-
def test_recursive_include(self):
l = make_local_path
# recursive-include
diff --git a/setuptools/tests/test_msvc.py b/setuptools/tests/test_msvc.py
index a0c76ea0..32d7a907 100644
--- a/setuptools/tests/test_msvc.py
+++ b/setuptools/tests/test_msvc.py
@@ -5,12 +5,9 @@ Tests for msvc support module.
import os
import contextlib
import distutils.errors
+import mock
import pytest
-try:
- from unittest import mock
-except ImportError:
- import mock
from . import contexts
diff --git a/setuptools/tests/test_namespaces.py b/setuptools/tests/test_namespaces.py
index 28c5e9de..721cad1e 100644
--- a/setuptools/tests/test_namespaces.py
+++ b/setuptools/tests/test_namespaces.py
@@ -7,12 +7,13 @@ import subprocess
import pytest
from . import namespaces
+from setuptools.command import test
class TestNamespaces:
- @pytest.mark.xfail(sys.version_info < (3, 3),
- reason="Requires PEP 420")
+ @pytest.mark.xfail(sys.version_info < (3, 5),
+ reason="Requires importlib.util.module_from_spec")
@pytest.mark.skipif(bool(os.environ.get("APPVEYOR")),
reason="https://github.com/pypa/setuptools/issues/851")
def test_mixed_site_and_non_site(self, tmpdir):
@@ -27,7 +28,6 @@ class TestNamespaces:
site_packages = tmpdir / 'site-packages'
path_packages = tmpdir / 'path-packages'
targets = site_packages, path_packages
- python_path = os.pathsep.join(map(str, targets))
# use pip to install to the target directory
install_cmd = [
'pip',
@@ -48,5 +48,58 @@ class TestNamespaces:
sys.executable,
'-c', 'import myns.pkgA; import myns.pkgB',
]
- env = dict(PYTHONPATH=python_path)
- subprocess.check_call(try_import, env=env)
+ with test.test.paths_on_pythonpath(map(str, targets)):
+ subprocess.check_call(try_import)
+
+ @pytest.mark.skipif(bool(os.environ.get("APPVEYOR")),
+ reason="https://github.com/pypa/setuptools/issues/851")
+ def test_pkg_resources_import(self, tmpdir):
+ """
+ Ensure that a namespace package doesn't break on import
+ of pkg_resources.
+ """
+ pkg = namespaces.build_namespace_package(tmpdir, 'myns.pkgA')
+ target = tmpdir / 'packages'
+ target.mkdir()
+ install_cmd = [
+ sys.executable,
+ '-m', 'easy_install',
+ '-d', str(target),
+ str(pkg),
+ ]
+ with test.test.paths_on_pythonpath([str(target)]):
+ subprocess.check_call(install_cmd)
+ namespaces.make_site_dir(target)
+ try_import = [
+ sys.executable,
+ '-c', 'import pkg_resources',
+ ]
+ with test.test.paths_on_pythonpath([str(target)]):
+ subprocess.check_call(try_import)
+
+ @pytest.mark.skipif(bool(os.environ.get("APPVEYOR")),
+ reason="https://github.com/pypa/setuptools/issues/851")
+ def test_namespace_package_installed_and_cwd(self, tmpdir):
+ """
+ Installing a namespace packages but also having it in the current
+ working directory, only one version should take precedence.
+ """
+ pkg_A = namespaces.build_namespace_package(tmpdir, 'myns.pkgA')
+ target = tmpdir / 'packages'
+ # use pip to install to the target directory
+ install_cmd = [
+ 'pip',
+ 'install',
+ str(pkg_A),
+ '-t', str(target),
+ ]
+ subprocess.check_call(install_cmd)
+ namespaces.make_site_dir(target)
+
+ # ensure that package imports and pkg_resources imports
+ pkg_resources_imp = [
+ sys.executable,
+ '-c', 'import pkg_resources; import myns.pkgA',
+ ]
+ with test.test.paths_on_pythonpath([str(target)]):
+ subprocess.check_call(pkg_resources_imp, cwd=str(pkg_A))
diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py
index f09dd78c..53e20d44 100644
--- a/setuptools/tests/test_packageindex.py
+++ b/setuptools/tests/test_packageindex.py
@@ -181,6 +181,48 @@ class TestPackageIndex:
res = setuptools.package_index.local_open(url)
assert 'content' in res.read()
+ def test_egg_fragment(self):
+ """
+ EGG fragments must comply to PEP 440
+ """
+ epoch = [
+ '',
+ '1!',
+ ]
+ releases = [
+ '0',
+ '0.0',
+ '0.0.0',
+ ]
+ pre = [
+ 'a0',
+ 'b0',
+ 'rc0',
+ ]
+ post = [
+ '.post0'
+ ]
+ dev = [
+ '.dev0',
+ ]
+ local = [
+ ('', ''),
+ ('+ubuntu.0', '+ubuntu.0'),
+ ('+ubuntu-0', '+ubuntu.0'),
+ ('+ubuntu_0', '+ubuntu.0'),
+ ]
+ versions = [
+ [''.join([e, r, p, l]) for l in ll]
+ for e in epoch
+ for r in releases
+ for p in sum([pre, post, dev], [''])
+ for ll in local]
+ for v, vc in versions:
+ dists = list(setuptools.package_index.distros_for_url(
+ 'http://example.com/example.zip#egg=example-' + v))
+ assert dists[0].version == ''
+ assert dists[1].version == vc
+
class TestContentCheckers:
def test_md5(self):
diff --git a/setuptools/tests/test_sandbox.py b/setuptools/tests/test_sandbox.py
index 929f0a5b..a3f1206d 100644
--- a/setuptools/tests/test_sandbox.py
+++ b/setuptools/tests/test_sandbox.py
@@ -7,13 +7,12 @@ import pytest
import pkg_resources
import setuptools.sandbox
-from setuptools.sandbox import DirectorySandbox
class TestSandbox:
def test_devnull(self, tmpdir):
- sandbox = DirectorySandbox(str(tmpdir))
- sandbox.run(self._file_writer(os.devnull))
+ with setuptools.sandbox.DirectorySandbox(str(tmpdir)):
+ self._file_writer(os.devnull)
@staticmethod
def _file_writer(path):
@@ -116,13 +115,17 @@ class TestExceptionSaver:
with open('/etc/foo', 'w'):
pass
- sandbox = DirectorySandbox(str(tmpdir))
with pytest.raises(setuptools.sandbox.SandboxViolation) as caught:
with setuptools.sandbox.save_modules():
setuptools.sandbox.hide_setuptools()
- sandbox.run(write_file)
+ with setuptools.sandbox.DirectorySandbox(str(tmpdir)):
+ write_file()
cmd, args, kwargs = caught.value.args
assert cmd == 'open'
assert args == ('/etc/foo', 'w')
assert kwargs == {}
+
+ msg = str(caught.value)
+ assert 'open' in msg
+ assert "('/etc/foo', 'w')" in msg
diff --git a/setuptools/tests/test_upload_docs.py b/setuptools/tests/test_upload_docs.py
index 5d50bb0b..a26e32a6 100644
--- a/setuptools/tests/test_upload_docs.py
+++ b/setuptools/tests/test_upload_docs.py
@@ -64,6 +64,8 @@ class TestUploadDocsTest:
)
body, content_type = upload_docs._build_multipart(data)
assert 'form-data' in content_type
+ assert "b'" not in content_type
+ assert 'b"' not in content_type
assert isinstance(body, bytes)
assert b'foo' in body
assert b'content' in body
diff --git a/setuptools/tests/test_virtualenv.py b/setuptools/tests/test_virtualenv.py
new file mode 100644
index 00000000..17b8793c
--- /dev/null
+++ b/setuptools/tests/test_virtualenv.py
@@ -0,0 +1,116 @@
+import glob
+import os
+
+from pytest import yield_fixture
+from pytest_fixture_config import yield_requires_config
+
+import pytest_virtualenv
+
+from .textwrap import DALS
+from .test_easy_install import make_nspkg_sdist
+
+
+@yield_requires_config(pytest_virtualenv.CONFIG, ['virtualenv_executable'])
+@yield_fixture(scope='function')
+def bare_virtualenv():
+ """ Bare virtualenv (no pip/setuptools/wheel).
+ """
+ with pytest_virtualenv.VirtualEnv(args=(
+ '--no-wheel',
+ '--no-pip',
+ '--no-setuptools',
+ )) as venv:
+ yield venv
+
+
+SOURCE_DIR = os.path.join(os.path.dirname(__file__), '../..')
+
+def test_clean_env_install(bare_virtualenv):
+ """
+ Check setuptools can be installed in a clean environment.
+ """
+ bare_virtualenv.run(' && '.join((
+ 'cd {source}',
+ 'python setup.py install',
+ )).format(source=SOURCE_DIR))
+
+def test_pip_upgrade_from_source(virtualenv):
+ """
+ Check pip can upgrade setuptools from source.
+ """
+ dist_dir = virtualenv.workspace
+ # Generate source distribution / wheel.
+ virtualenv.run(' && '.join((
+ 'cd {source}',
+ 'python setup.py -q sdist -d {dist}',
+ 'python setup.py -q bdist_wheel -d {dist}',
+ )).format(source=SOURCE_DIR, dist=dist_dir))
+ sdist = glob.glob(os.path.join(dist_dir, '*.zip'))[0]
+ wheel = glob.glob(os.path.join(dist_dir, '*.whl'))[0]
+ # Then update from wheel.
+ virtualenv.run('pip install ' + wheel)
+ # And finally try to upgrade from source.
+ virtualenv.run('pip install --no-cache-dir --upgrade ' + sdist)
+
+def test_test_command_install_requirements(bare_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))
+ def sdist(distname, version):
+ dist_path = tmpdir.join('%s-%s.tar.gz' % (distname, version))
+ make_nspkg_sdist(str(dist_path), distname, version)
+ return dist_path
+ dependency_links = [
+ str(dist_path)
+ for dist_path in (
+ sdist('foobar', '2.4'),
+ sdist('bits', '4.2'),
+ sdist('bobs', '6.0'),
+ sdist('pieces', '0.6'),
+ )
+ ]
+ with tmpdir.join('setup.py').open('w') as fp:
+ fp.write(DALS(
+ '''
+ from setuptools import setup
+
+ setup(
+ dependency_links={dependency_links!r},
+ install_requires=[
+ 'barbazquux1; sys_platform in ""',
+ 'foobar==2.4',
+ ],
+ setup_requires='bits==4.2',
+ tests_require="""
+ bobs==6.0
+ """,
+ extras_require={{
+ 'test': ['barbazquux2'],
+ ':"" in sys_platform': 'pieces==0.6',
+ ':python_version > "1"': """
+ pieces
+ foobar
+ """,
+ }}
+ )
+ '''.format(dependency_links=dependency_links)))
+ with tmpdir.join('test.py').open('w') as fp:
+ fp.write(DALS(
+ '''
+ import foobar
+ import bits
+ import bobs
+ import pieces
+
+ open('success', 'w').close()
+ '''))
+ # Run test command for test package.
+ bare_virtualenv.run(' && '.join((
+ 'cd {tmpdir}',
+ 'python setup.py test -s test',
+ )).format(tmpdir=tmpdir))
+ assert tmpdir.join('success').check()