blob: abb953a8fa40547730d9ad2b98e0dfe8b0fe0a3b [file] [log] [blame]
import contextlib
import pytest
from distutils.errors import DistutilsOptionError, DistutilsFileError
from setuptools.dist import Distribution
from setuptools.config import ConfigHandler, read_configuration
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:
setup_py = (
'from setuptools import setup\n'
'setup()\n'
)
tmpdir.join('setup.py').write(setup_py)
config = tmpdir.join('setup.cfg')
config.write(setup_cfg)
package_dir, init_file = make_package_dir('fake_package', tmpdir)
init_file.write(
'VERSION = (1, 2, 3)\n'
'\n'
'VERSION_MAJOR = 1'
'\n'
'def get_version():\n'
' return [3, 4, 5, "dev"]\n'
'\n'
)
return package_dir, config
@contextlib.contextmanager
def get_dist(tmpdir, kwargs_initial=None, parse=True):
kwargs_initial = kwargs_initial or {}
with tmpdir.as_cwd():
dist = Distribution(kwargs_initial)
dist.script_name = 'setup.py'
parse and dist.parse_config_files()
yield dist
def test_parsers_implemented():
with pytest.raises(NotImplementedError):
handler = ErrConfigHandler(None, {})
handler.parsers
class TestConfigurationReader:
def test_basic(self, tmpdir):
_, config = fake_env(
tmpdir,
'[metadata]\n'
'version = 10.1.1\n'
'keywords = one, two\n'
'\n'
'[options]\n'
'scripts = bin/a.py, bin/b.py\n'
)
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']
def test_no_config(self, tmpdir):
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:
def test_basic(self, tmpdir):
fake_env(
tmpdir,
'[metadata]\n'
'version = 10.1.1\n'
'description = Some description\n'
'long_description_content_type = text/something\n'
'long_description = file: README\n'
'name = fake_name\n'
'keywords = one, two\n'
'provides = package, package.sub\n'
'license = otherlic\n'
'download_url = http://test.test.com/test/\n'
'maintainer_email = test@test.com\n'
)
tmpdir.join('README').write('readme contents\nline2')
meta_initial = {
# This will be used so `otherlic` won't replace it.
'license': 'BSD 3-Clause License',
}
with get_dist(tmpdir, meta_initial) as dist:
metadata = dist.metadata
assert metadata.version == '10.1.1'
assert metadata.description == 'Some description'
assert metadata.long_description_content_type == 'text/something'
assert metadata.long_description == 'readme contents\nline2'
assert metadata.provides == ['package', 'package.sub']
assert metadata.license == 'BSD 3-Clause License'
assert metadata.name == 'fake_name'
assert metadata.keywords == ['one', 'two']
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(
tmpdir,
'[metadata]\n'
'long_description = file: ../../README\n'
)
with get_dist(tmpdir, parse=False) as dist:
with pytest.raises(DistutilsOptionError):
dist.parse_config_files() # file: out of sandbox
def test_aliases(self, tmpdir):
fake_env(
tmpdir,
'[metadata]\n'
'author-email = test@test.com\n'
'home-page = http://test.test.com/test/\n'
'summary = Short summary\n'
'platform = a, b\n'
'classifier =\n'
' Framework :: Django\n'
' Programming Language :: Python :: 3.5\n'
)
with get_dist(tmpdir) as dist:
metadata = dist.metadata
assert metadata.author_email == 'test@test.com'
assert metadata.url == 'http://test.test.com/test/'
assert metadata.description == 'Short summary'
assert metadata.platforms == ['a', 'b']
assert metadata.classifiers == [
'Framework :: Django',
'Programming Language :: Python :: 3.5',
]
def test_multiline(self, tmpdir):
fake_env(
tmpdir,
'[metadata]\n'
'name = fake_name\n'
'keywords =\n'
' one\n'
' two\n'
'classifiers =\n'
' Framework :: Django\n'
' Programming Language :: Python :: 3.5\n'
)
with get_dist(tmpdir) as dist:
metadata = dist.metadata
assert metadata.keywords == ['one', 'two']
assert metadata.classifiers == [
'Framework :: Django',
'Programming Language :: Python :: 3.5',
]
def test_dict(self, tmpdir):
fake_env(
tmpdir,
'[metadata]\n'
'project_urls =\n'
' Link One = https://example.com/one/\n'
' Link Two = https://example.com/two/\n'
)
with get_dist(tmpdir) as dist:
metadata = dist.metadata
assert metadata.project_urls == {
'Link One': 'https://example.com/one/',
'Link Two': 'https://example.com/two/',
}
def test_version(self, tmpdir):
_, config = fake_env(
tmpdir,
'[metadata]\n'
'version = attr: fake_package.VERSION\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1.2.3'
config.write(
'[metadata]\n'
'version = attr: fake_package.get_version\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '3.4.5.dev'
config.write(
'[metadata]\n'
'version = attr: fake_package.VERSION_MAJOR\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '1'
subpack = tmpdir.join('fake_package').mkdir('subpackage')
subpack.join('__init__.py').write('')
subpack.join('submodule.py').write('VERSION = (2016, 11, 26)')
config.write(
'[metadata]\n'
'version = attr: fake_package.subpackage.submodule.VERSION\n'
)
with get_dist(tmpdir) as dist:
assert dist.metadata.version == '2016.11.26'
def test_unknown_meta_item(self, tmpdir):
fake_env(
tmpdir,
'[metadata]\n'
'name = fake_name\n'
'unknown = some\n'
)
with get_dist(tmpdir, parse=False) as dist:
dist.parse_config_files() # Skip unknown.
def test_usupported_section(self, tmpdir):
fake_env(
tmpdir,
'[metadata.some]\n'
'key = val\n'
)
with get_dist(tmpdir, parse=False) as dist:
with pytest.raises(DistutilsOptionError):
dist.parse_config_files()
def test_classifiers(self, tmpdir):
expected = set([
'Framework :: Django',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
])
# From file.
_, config = fake_env(
tmpdir,
'[metadata]\n'
'classifiers = file: classifiers\n'
)
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 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
class TestOptions:
def test_basic(self, tmpdir):
fake_env(
tmpdir,
'[options]\n'
'zip_safe = True\n'
'use_2to3 = 1\n'
'include_package_data = yes\n'
'package_dir = b=c, =src\n'
'packages = pack_a, pack_b.subpack\n'
'namespace_packages = pack1, pack2\n'
'use_2to3_fixers = your.fixers, or.here\n'
'use_2to3_exclude_fixers = one.here, two.there\n'
'convert_2to3_doctests = src/tests/one.txt, src/two.txt\n'
'scripts = bin/one.py, bin/two.py\n'
'eager_resources = bin/one.py, bin/two.py\n'
'install_requires = docutils>=0.3; pack ==1.1, ==1.3; hey\n'
'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'
'python_requires = >=1.0, !=2.8\n'
'py_modules = module1, module2\n'
)
with get_dist(tmpdir) as dist:
assert dist.zip_safe
assert dist.use_2to3
assert dist.include_package_data
assert dist.package_dir == {'': 'src', 'b': 'c'}
assert dist.packages == ['pack_a', 'pack_b.subpack']
assert dist.namespace_packages == ['pack1', 'pack2']
assert dist.use_2to3_fixers == ['your.fixers', 'or.here']
assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there']
assert dist.convert_2to3_doctests == ([
'src/tests/one.txt', 'src/two.txt'])
assert dist.scripts == ['bin/one.py', 'bin/two.py']
assert dist.dependency_links == ([
'http://some.com/here/1',
'http://some.com/there/2'
])
assert dist.install_requires == ([
'docutils>=0.3',
'pack==1.1,==1.3',
'hey'
])
assert dist.setup_requires == ([
'docutils>=0.3',
'spack ==1.1, ==1.3',
'there'
])
assert dist.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(
tmpdir,
'[options]\n'
'package_dir = \n'
' b=c\n'
' =src\n'
'packages = \n'
' pack_a\n'
' pack_b.subpack\n'
'namespace_packages = \n'
' pack1\n'
' pack2\n'
'use_2to3_fixers = \n'
' your.fixers\n'
' or.here\n'
'use_2to3_exclude_fixers = \n'
' one.here\n'
' two.there\n'
'convert_2to3_doctests = \n'
' src/tests/one.txt\n'
' src/two.txt\n'
'scripts = \n'
' bin/one.py\n'
' bin/two.py\n'
'eager_resources = \n'
' bin/one.py\n'
' bin/two.py\n'
'install_requires = \n'
' docutils>=0.3\n'
' pack ==1.1, ==1.3\n'
' hey\n'
'tests_require = \n'
' mock==0.7.2\n'
' pytest\n'
'setup_requires = \n'
' docutils>=0.3\n'
' spack ==1.1, ==1.3\n'
' there\n'
'dependency_links = \n'
' http://some.com/here/1\n'
' http://some.com/there/2\n'
)
with get_dist(tmpdir) as dist:
assert dist.package_dir == {'': 'src', 'b': 'c'}
assert dist.packages == ['pack_a', 'pack_b.subpack']
assert dist.namespace_packages == ['pack1', 'pack2']
assert dist.use_2to3_fixers == ['your.fixers', 'or.here']
assert dist.use_2to3_exclude_fixers == ['one.here', 'two.there']
assert dist.convert_2to3_doctests == (
['src/tests/one.txt', 'src/two.txt'])
assert dist.scripts == ['bin/one.py', 'bin/two.py']
assert dist.dependency_links == ([
'http://some.com/here/1',
'http://some.com/there/2'
])
assert dist.install_requires == ([
'docutils>=0.3',
'pack==1.1,==1.3',
'hey'
])
assert dist.setup_requires == ([
'docutils>=0.3',
'spack ==1.1, ==1.3',
'there'
])
assert dist.tests_require == ['mock==0.7.2', 'pytest']
def test_package_dir_fail(self, tmpdir):
fake_env(
tmpdir,
'[options]\n'
'package_dir = a b\n'
)
with get_dist(tmpdir, parse=False) as dist:
with pytest.raises(DistutilsOptionError):
dist.parse_config_files()
def test_package_data(self, tmpdir):
fake_env(
tmpdir,
'[options.package_data]\n'
'* = *.txt, *.rst\n'
'hello = *.msg\n'
'\n'
'[options.exclude_package_data]\n'
'* = fake1.txt, fake2.txt\n'
'hello = *.dat\n'
)
with get_dist(tmpdir) as dist:
assert dist.package_data == {
'': ['*.txt', '*.rst'],
'hello': ['*.msg'],
}
assert dist.exclude_package_data == {
'': ['fake1.txt', 'fake2.txt'],
'hello': ['*.dat'],
}
def test_packages(self, tmpdir):
fake_env(
tmpdir,
'[options]\n'
'packages = find:\n'
)
with get_dist(tmpdir) as dist:
assert dist.packages == ['fake_package']
def test_find_directive(self, tmpdir):
dir_package, config = fake_env(
tmpdir,
'[options]\n'
'packages = find:\n'
)
dir_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,
'[options.extras_require]\n'
'pdf = ReportLab>=1.2; RXP\n'
'rest = \n'
' docutils>=0.3\n'
' pack ==1.1, ==1.3\n'
)
with get_dist(tmpdir) as dist:
assert dist.extras_require == {
'pdf': ['ReportLab>=1.2', 'RXP'],
'rest': ['docutils>=0.3', 'pack==1.1,==1.3']
}
assert dist.metadata.provides_extras == set(['pdf', 'rest'])
def test_entry_points(self, tmpdir):
_, config = fake_env(
tmpdir,
'[options.entry_points]\n'
'group1 = point1 = pack.module:func, '
'.point2 = pack.module2:func_rest [rest]\n'
'group2 = point3 = pack.module:func2\n'
)
with get_dist(tmpdir) as dist:
assert dist.entry_points == {
'group1': [
'point1 = pack.module:func',
'.point2 = pack.module2:func_rest [rest]',
],
'group2': ['point3 = pack.module:func2']
}
expected = (
'[blogtool.parsers]\n'
'.rst = some.nested.module:SomeClass.some_classmethod[reST]\n'
)
tmpdir.join('entry_points').write(expected)
# From file.
config.write(
'[options]\n'
'entry_points = file: entry_points\n'
)
with get_dist(tmpdir) as dist:
assert dist.entry_points == expected