From f541a7b12a52f18e98b24ac92ba778055f66ce75 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 19:28:34 +0200 Subject: [PATCH 01/10] fix #1419 PEP420: add find_namespace: directive --- setuptools/config.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/setuptools/config.py b/setuptools/config.py index 5f908cf129..cb63ac1785 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -8,7 +8,7 @@ from distutils.errors import DistutilsOptionError, DistutilsFileError from setuptools.extern.packaging.version import LegacyVersion, parse -from setuptools.extern.six import string_types +from setuptools.extern.six import string_types, PY3 __metaclass__ = type @@ -516,20 +516,30 @@ def _parse_packages(self, value): :rtype: list """ find_directive = 'find:' + find_namespace_directive = 'find_namespace:' + findns = False if not value.startswith(find_directive): + if value.startswith(find_namespace_directive): + if not PY3: + raise DistutilsOptionError('find_namespace directive is unsupported on Python < 3.3') + findns = True + else: return self._parse_list(value) # Read function arguments from a dedicated section. find_kwargs = self.parse_section_packages__find( self.sections.get('packages.find', {})) - from setuptools import find_packages + if findns: + from setuptools import find_packages_ns as find_packages + else: + from setuptools import find_packages return find_packages(**find_kwargs) def parse_section_packages__find(self, section_options): - """Parses `packages.find` configuration file section. + """Parses `packages.find[ns]` configuration file section. To be used in conjunction with _parse_packages(). From 8eeca1e17bc01cd8cbb71a5c37ae0f9ba0e1a59e Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 19:28:55 +0200 Subject: [PATCH 02/10] fix #1419 PEP420: add find_namespace: directive to documentation --- docs/setuptools.txt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/setuptools.txt b/docs/setuptools.txt index 0660e14d5d..f990827039 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -2389,8 +2389,8 @@ Metadata and options are set in the config sections of the same name. * In some cases, complex values can be provided in dedicated subsections for clarity. -* Some keys allow ``file:``, ``attr:``, and ``find:`` directives in order to - cover common usecases. +* Some keys allow ``file:``, ``attr:``, and ``find:`` and ``find_namespace:`` directives i + order to cover common usecases. * Unknown keys are ignored. @@ -2479,7 +2479,7 @@ eager_resources list-comma dependency_links list-comma tests_require list-semi include_package_data bool -packages find:, list-comma +packages find:, find_namespace:, list-comma package_dir dict package_data section exclude_package_data section @@ -2489,10 +2489,13 @@ py_modules list-comma .. note:: - **packages** - The ``find:`` directive can be further configured + **packages** - The ``find:`` and ``find_namespace:`` directive can be further configured in a dedicated subsection ``options.packages.find``. This subsection - accepts the same keys as the `setuptools.find` function: + accepts the same keys as the `setuptools.find_packages` and the + `setuptools.find_packages_ns` function: ``where``, ``include``, and ``exclude``. + + **find_namespace directive** - The ``find_namespace:`` directive is supported since Python >=3.3. Configuration API From 101b616558293016fc43fecd70c2119a8b9344d8 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 20:00:02 +0200 Subject: [PATCH 03/10] fix #1419 PEP420: add tests --- setuptools/tests/test_config.py | 64 +++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index 19b3763363..d87f6d0b82 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -4,18 +4,23 @@ from mock import patch from setuptools.dist import Distribution, _Distribution from setuptools.config import ConfigHandler, read_configuration +from setuptools.extern.six import PY2, PY3 +py2_only = pytest.mark.xfail(not PY2, reason="Test runs on Python 2 only") +py3_only = pytest.mark.xfail(not PY3, reason="Test runs on Python 3 only") class ErrConfigHandler(ConfigHandler): """Erroneous handler. Fails to implement required methods.""" -def make_package_dir(name, base_dir): +def make_package_dir(name, base_dir, ns=False): dir_package = base_dir for dir_name in name.split('/'): dir_package = dir_package.mkdir(dir_name) - init_file = dir_package.join('__init__.py') - init_file.write('') + init_file = None + if not ns: + init_file = dir_package.join('__init__.py') + init_file.write('') return dir_package, init_file @@ -596,6 +601,59 @@ def test_find_directive(self, tmpdir): assert set(dist.packages) == set( ['fake_package', 'fake_package.sub_two']) + @py2_only + def test_find_namespace_directive_fails_on_py2(self, tmpdir): + dir_package, config = fake_env( + tmpdir, + '[options]\n' + 'packages = find_namespace:\n' + ) + + with pytest.raises(DistutilsOptionError): + with get_dist(tmpdir) as dist: + dist.parse_config_files() + + @py3_only + def test_find_namespace_directive(self, tmpdir): + dir_package, config = fake_env( + tmpdir, + '[options]\n' + 'packages = find_namespace:\n' + ) + + dir_sub_one, _ = make_package_dir('sub_one', dir_package) + dir_sub_two, _ = make_package_dir('sub_two', dir_package, ns=True) + + 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_namespace:\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_namespace:\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, From 21a67f6f4f50c561e295852b594e5f6e6866f8b4 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 20:13:13 +0200 Subject: [PATCH 04/10] fix #1419 PEP420: clean up code --- setuptools/config.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/setuptools/config.py b/setuptools/config.py index cb63ac1785..16eb8a0e14 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -515,17 +515,15 @@ def _parse_packages(self, value): :param value: :rtype: list """ - find_directive = 'find:' - find_namespace_directive = 'find_namespace:' - - findns = False - if not value.startswith(find_directive): - if value.startswith(find_namespace_directive): - if not PY3: - raise DistutilsOptionError('find_namespace directive is unsupported on Python < 3.3') - findns = True - else: - return self._parse_list(value) + find_directives = ['find:', 'find_namespace:'] + trimmed_value = value.strip() + + if not trimmed_value in find_directives: + return self._parse_list(value) + + findns = trimmed_value == find_directives[1] + if findns and not PY3: + raise DistutilsOptionError('find_namespace: directive is unsupported on Python < 3.3') # Read function arguments from a dedicated section. find_kwargs = self.parse_section_packages__find( From 091a720145d71816501c153978c68f929add3c56 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 20:31:43 +0200 Subject: [PATCH 05/10] fix #1419 PEP420: fix typo in documentation --- docs/setuptools.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/setuptools.txt b/docs/setuptools.txt index f990827039..f3e31b831f 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -2389,7 +2389,7 @@ Metadata and options are set in the config sections of the same name. * In some cases, complex values can be provided in dedicated subsections for clarity. -* Some keys allow ``file:``, ``attr:``, and ``find:`` and ``find_namespace:`` directives i +* Some keys allow ``file:``, ``attr:``, and ``find:`` and ``find_namespace:`` directives in order to cover common usecases. * Unknown keys are ignored. From 5f1d155283ca2f4e5851087349fa1cad44e27a83 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 20:32:11 +0200 Subject: [PATCH 06/10] fix #1419 PEP420: fix typo in documentation --- setuptools/config.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setuptools/config.py b/setuptools/config.py index 16eb8a0e14..23ca20d537 100644 --- a/setuptools/config.py +++ b/setuptools/config.py @@ -519,25 +519,25 @@ def _parse_packages(self, value): trimmed_value = value.strip() if not trimmed_value in find_directives: - return self._parse_list(value) + return self._parse_list(value) findns = trimmed_value == find_directives[1] if findns and not PY3: - raise DistutilsOptionError('find_namespace: directive is unsupported on Python < 3.3') + raise DistutilsOptionError('find_namespace: directive is unsupported on Python < 3.3') # Read function arguments from a dedicated section. find_kwargs = self.parse_section_packages__find( self.sections.get('packages.find', {})) if findns: - from setuptools import find_packages_ns as find_packages + from setuptools import find_packages_ns as find_packages else: - from setuptools import find_packages + from setuptools import find_packages return find_packages(**find_kwargs) def parse_section_packages__find(self, section_options): - """Parses `packages.find[ns]` configuration file section. + """Parses `packages.find` configuration file section. To be used in conjunction with _parse_packages(). From 924f41cc85ca628c6dc6d6abe4c69463197f6039 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 20:38:35 +0200 Subject: [PATCH 07/10] fix #1419 PEP420: clean up code --- setuptools/tests/test_config.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index d87f6d0b82..fe70481eec 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -625,9 +625,9 @@ def test_find_namespace_directive(self, tmpdir): dir_sub_two, _ = make_package_dir('sub_two', dir_package, ns=True) with get_dist(tmpdir) as dist: - assert set(dist.packages) == set([ + assert set(dist.packages) == { 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one' - ]) + } config.write( '[options]\n' @@ -651,8 +651,9 @@ def test_find_namespace_directive(self, tmpdir): ' fake_package.sub_one\n' ) with get_dist(tmpdir) as dist: - assert set(dist.packages) == set( - ['fake_package', 'fake_package.sub_two']) + assert set(dist.packages) == { + 'fake_package', 'fake_package.sub_two' + } def test_extras_require(self, tmpdir): fake_env( From 9b26ea5005d2cd1386c77018912d5763abff27dc Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Wed, 11 Jul 2018 20:41:10 +0200 Subject: [PATCH 08/10] fix #1419 PEP420: add changelog entry --- changelog.d/1420.change.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/1420.change.rst diff --git a/changelog.d/1420.change.rst b/changelog.d/1420.change.rst new file mode 100644 index 0000000000..6967adccb0 --- /dev/null +++ b/changelog.d/1420.change.rst @@ -0,0 +1 @@ +Add find_namespace: directive to config parser From e1e8659edf8db7c67a8886885dc20f95fdae60e4 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Wed, 11 Jul 2018 16:28:37 -0400 Subject: [PATCH 09/10] fixup! fix #1419 PEP420: add tests --- setuptools/tests/test_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index fe70481eec..23e14796df 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -6,8 +6,8 @@ from setuptools.config import ConfigHandler, read_configuration from setuptools.extern.six import PY2, PY3 -py2_only = pytest.mark.xfail(not PY2, reason="Test runs on Python 2 only") -py3_only = pytest.mark.xfail(not PY3, reason="Test runs on Python 3 only") +py2_only = pytest.mark.skipif(not PY2, reason="Test runs on Python 2 only") +py3_only = pytest.mark.skipif(not PY3, reason="Test runs on Python 3 only") class ErrConfigHandler(ConfigHandler): """Erroneous handler. Fails to implement required methods.""" From 3c30cf3d7c158452d1336c6937b826c95c096c06 Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Thu, 12 Jul 2018 17:59:23 +0200 Subject: [PATCH 10/10] fix #1419 PEP420: cleanup code refactor markers --- setuptools/tests/__init__.py | 12 ++++++++++++ setuptools/tests/test_config.py | 9 +++------ setuptools/tests/test_find_packages.py | 4 ++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py index 54dd7d2b20..5f4a1c2958 100644 --- a/setuptools/tests/__init__.py +++ b/setuptools/tests/__init__.py @@ -2,5 +2,17 @@ import pytest +from setuptools.extern.six import PY2, PY3 + + +__all__ = [ + 'fail_on_ascii', 'py2_only', 'py3_only' +] + + is_ascii = locale.getpreferredencoding() == 'ANSI_X3.4-1968' fail_on_ascii = pytest.mark.xfail(is_ascii, reason="Test fails in this locale") + + +py2_only = pytest.mark.skipif(not PY2, reason="Test runs on Python 2 only") +py3_only = pytest.mark.skipif(not PY3, reason="Test runs on Python 3 only") diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py index 23e14796df..9a4c83906b 100644 --- a/setuptools/tests/test_config.py +++ b/setuptools/tests/test_config.py @@ -4,10 +4,7 @@ from mock import patch from setuptools.dist import Distribution, _Distribution from setuptools.config import ConfigHandler, read_configuration -from setuptools.extern.six import PY2, PY3 - -py2_only = pytest.mark.skipif(not PY2, reason="Test runs on Python 2 only") -py3_only = pytest.mark.skipif(not PY3, reason="Test runs on Python 3 only") +from setuptools.tests import py2_only, py3_only class ErrConfigHandler(ConfigHandler): """Erroneous handler. Fails to implement required methods.""" @@ -610,8 +607,8 @@ def test_find_namespace_directive_fails_on_py2(self, tmpdir): ) with pytest.raises(DistutilsOptionError): - with get_dist(tmpdir) as dist: - dist.parse_config_files() + with get_dist(tmpdir) as dist: + dist.parse_config_files() @py3_only def test_find_namespace_directive(self, tmpdir): diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py index 02ae5a946d..f6e75053a7 100644 --- a/setuptools/tests/test_find_packages.py +++ b/setuptools/tests/test_find_packages.py @@ -7,10 +7,10 @@ import pytest +from setuptools.tests import py3_only + from setuptools.extern.six import PY3 from setuptools import find_packages - -py3_only = pytest.mark.xfail(not PY3, reason="Test runs on Python 3 only") if PY3: from setuptools import find_packages_ns