summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2018-05-18 15:23:43 -0400
committerGitHub <noreply@github.com>2018-05-18 15:23:43 -0400
commit239ff9bd9fe9c38f811fab160491e34dbad5cbeb (patch)
treec2f1033b537db03a7372b47061f7b8bd7340b0f9
parent811c4feac09125d6946c6a159557c4e610fa58de (diff)
parent07cd2e4e716264fd51aededcb77cefe37aafb25a (diff)
downloadpython-setuptools-git-239ff9bd9fe9c38f811fab160491e34dbad5cbeb.tar.gz
Merge pull request #1343 from ianw/long-descr-type
Allow setting long_description_content_type externally
-rw-r--r--changelog.d/1343.misc.rst4
-rw-r--r--setuptools/dist.py36
-rw-r--r--setuptools/tests/test_config.py43
3 files changed, 69 insertions, 14 deletions
diff --git a/changelog.d/1343.misc.rst b/changelog.d/1343.misc.rst
new file mode 100644
index 00000000..644320f4
--- /dev/null
+++ b/changelog.d/1343.misc.rst
@@ -0,0 +1,4 @@
+The ``setuptools`` specific ``long_description_content_type``,
+``project_urls`` and ``provides_extras`` fields are now set
+consistently after any ``distutils`` ``setup_keywords`` calls,
+allowing them to override values.
diff --git a/setuptools/dist.py b/setuptools/dist.py
index 321ab6b7..6ee4a97f 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -328,6 +328,12 @@ class Distribution(Distribution_parse_config_files, _Distribution):
distribution for the included and excluded features.
"""
+ _DISTUTILS_UNSUPPORTED_METADATA = {
+ 'long_description_content_type': None,
+ 'project_urls': dict,
+ 'provides_extras': set,
+ }
+
_patched_dist = None
def patch_missing_pkg_info(self, attrs):
@@ -353,25 +359,29 @@ class Distribution(Distribution_parse_config_files, _Distribution):
self.require_features = []
self.features = {}
self.dist_files = []
+ # Filter-out setuptools' specific options.
self.src_root = attrs.pop("src_root", None)
self.patch_missing_pkg_info(attrs)
- self.project_urls = attrs.get('project_urls', {})
self.dependency_links = attrs.pop('dependency_links', [])
self.setup_requires = attrs.pop('setup_requires', [])
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
vars(self).setdefault(ep.name, None)
- _Distribution.__init__(self, attrs)
-
- # The project_urls attribute may not be supported in distutils, so
- # prime it here from our value if not automatically set
- self.metadata.project_urls = getattr(
- self.metadata, 'project_urls', self.project_urls)
- self.metadata.long_description_content_type = attrs.get(
- 'long_description_content_type'
- )
- self.metadata.provides_extras = getattr(
- self.metadata, 'provides_extras', set()
- )
+ _Distribution.__init__(self, {
+ k: v for k, v in attrs.items()
+ if k not in self._DISTUTILS_UNSUPPORTED_METADATA
+ })
+
+ # Fill-in missing metadata fields not supported by distutils.
+ # Note some fields may have been set by other tools (e.g. pbr)
+ # above; they are taken preferrentially to setup() arguments
+ for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items():
+ for source in self.metadata.__dict__, attrs:
+ if option in source:
+ value = source[option]
+ break
+ else:
+ value = default() if default else None
+ setattr(self.metadata, option, value)
if isinstance(self.metadata.version, numbers.Number):
# Some people apparently take "version number" too literally :)
diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py
index de7c8b4d..19b37633 100644
--- a/setuptools/tests/test_config.py
+++ b/setuptools/tests/test_config.py
@@ -1,7 +1,8 @@
import contextlib
import pytest
from distutils.errors import DistutilsOptionError, DistutilsFileError
-from setuptools.dist import Distribution
+from mock import patch
+from setuptools.dist import Distribution, _Distribution
from setuptools.config import ConfigHandler, read_configuration
@@ -645,3 +646,43 @@ class TestOptions:
with get_dist(tmpdir) as dist:
assert dist.entry_points == expected
+
+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
+ # _Distribution.__init__ ().
+ #
+ # It's possible distutils calls out to various keyword
+ # implementations (i.e. distutils.setup_keywords entry points)
+ # that may set a range of variables.
+ #
+ # This wraps distutil's Distribution.__init__ and simulates
+ # pbr or something else setting these values.
+ def _fake_distribution_init(self, dist, attrs):
+ saved_dist_init(dist, attrs)
+ # see self._DISTUTUILS_UNSUPPORTED_METADATA
+ setattr(dist.metadata, 'long_description_content_type',
+ 'text/something')
+ # Test overwrite setup() args
+ setattr(dist.metadata, 'project_urls', {
+ 'Link One': 'https://example.com/one/',
+ 'Link Two': 'https://example.com/two/',
+ })
+ return None
+
+ @patch.object(_Distribution, '__init__', autospec=True)
+ def test_external_setters(self, mock_parent_init, tmpdir):
+ mock_parent_init.side_effect = self._fake_distribution_init
+
+ dist = Distribution(attrs={
+ 'project_urls': {
+ 'will_be': 'ignored'
+ }
+ })
+
+ assert dist.metadata.long_description_content_type == 'text/something'
+ assert dist.metadata.project_urls == {
+ 'Link One': 'https://example.com/one/',
+ 'Link Two': 'https://example.com/two/',
+ }