| 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 |