summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Wienand <iwienand@redhat.com>2018-04-30 19:08:58 +1000
committerIan Wienand <iwienand@redhat.com>2018-05-17 07:22:25 +1000
commit07cd2e4e716264fd51aededcb77cefe37aafb25a (patch)
tree08c8395e42ab13e3d66ea5f903840993909aefb6
parent1252d1b3b34261acd6c8051c4fe97f206a7118b7 (diff)
downloadpython-setuptools-git-07cd2e4e716264fd51aededcb77cefe37aafb25a.tar.gz
Allow setting long_description_content_type externally
Some tools, such as PBR, might want to set long_description_content_type during the parent object's Distribution.__init__() call (during distutils setup_keywords entry points). However, that field is currently unconditionally overwritten after these calls, erasing the value. We would rather not duplicate the existing method of copying into dist.metadata as done with project_urls. This preserves the fields within Distribution.metadata described by self._DISTUTIULS_UNUPPORTED_METADATA, or otherwise takes it from arguments. A test case that simulates setting the long description and overriding the arguments is added.
-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 17ac09c8..91471306 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
@@ -598,3 +599,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/',
+ }