summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason R. Coombs <jaraco@jaraco.com>2021-04-14 19:04:50 -0400
committerGitHub <noreply@github.com>2021-04-14 19:04:50 -0400
commit07eda18d6c4cf987ea57a2f9cf3deff9f0bf0105 (patch)
tree5b8a940400c3c5e408edf6d2e974cc3e51b3b542
parent1d330f9daded60f0d7721b51d8027494c5bf11d3 (diff)
parentc18ed8706d759e11d7bb7e9070a1897ee2f1e979 (diff)
downloadpython-setuptools-git-07eda18d6c4cf987ea57a2f9cf3deff9f0bf0105.tar.gz
Merge pull request #2635 from cdce8p/refactor-dist
Refactor ``read_pkg_file``
-rw-r--r--setuptools/dist.py83
-rw-r--r--setuptools/tests/test_dist.py40
2 files changed, 95 insertions, 28 deletions
diff --git a/setuptools/dist.py b/setuptools/dist.py
index 7cebcb37..c7af35dc 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -16,6 +16,8 @@ from distutils.util import strtobool
from distutils.debug import DEBUG
from distutils.fancy_getopt import translate_longopt
import itertools
+import textwrap
+from typing import List, Optional, TYPE_CHECKING
from collections import defaultdict
from email import message_from_file
@@ -36,6 +38,9 @@ from setuptools.monkey import get_unpatched
from setuptools.config import parse_configuration
import pkg_resources
+if TYPE_CHECKING:
+ from email.message import Message
+
__import__('setuptools.extern.packaging.specifiers')
__import__('setuptools.extern.packaging.version')
@@ -67,53 +72,75 @@ def get_metadata_version(self):
return mv
-def read_pkg_file(self, file):
- """Reads the metadata values from a file object."""
- msg = message_from_file(file)
+def rfc822_unescape(content: str) -> str:
+ """Reverse RFC-822 escaping by removing leading whitespaces from content."""
+ lines = content.splitlines()
+ if len(lines) == 1:
+ return lines[0].lstrip()
+ return '\n'.join(
+ (lines[0].lstrip(),
+ textwrap.dedent('\n'.join(lines[1:]))))
+
+
+def _read_field_from_msg(msg: "Message", field: str) -> Optional[str]:
+ """Read Message header field."""
+ value = msg[field]
+ if value == 'UNKNOWN':
+ return None
+ return value
+
- def _read_field(name):
- value = msg[name]
- if value == 'UNKNOWN':
- return None
+def _read_field_unescaped_from_msg(msg: "Message", field: str) -> Optional[str]:
+ """Read Message header field and apply rfc822_unescape."""
+ value = _read_field_from_msg(msg, field)
+ if value is None:
return value
+ return rfc822_unescape(value)
- def _read_list(name):
- values = msg.get_all(name, None)
- if values == []:
- return None
- return values
+
+def _read_list_from_msg(msg: "Message", field: str) -> Optional[List[str]]:
+ """Read Message header field and return all results as list."""
+ values = msg.get_all(field, None)
+ if values == []:
+ return None
+ return values
+
+
+def read_pkg_file(self, file):
+ """Reads the metadata values from a file object."""
+ msg = message_from_file(file)
self.metadata_version = StrictVersion(msg['metadata-version'])
- self.name = _read_field('name')
- self.version = _read_field('version')
- self.description = _read_field('summary')
+ self.name = _read_field_from_msg(msg, 'name')
+ self.version = _read_field_from_msg(msg, 'version')
+ self.description = _read_field_from_msg(msg, 'summary')
# we are filling author only.
- self.author = _read_field('author')
+ self.author = _read_field_from_msg(msg, 'author')
self.maintainer = None
- self.author_email = _read_field('author-email')
+ self.author_email = _read_field_from_msg(msg, 'author-email')
self.maintainer_email = None
- self.url = _read_field('home-page')
- self.license = _read_field('license')
+ self.url = _read_field_from_msg(msg, 'home-page')
+ self.license = _read_field_from_msg(msg, 'license')
if 'download-url' in msg:
- self.download_url = _read_field('download-url')
+ self.download_url = _read_field_from_msg(msg, 'download-url')
else:
self.download_url = None
- self.long_description = _read_field('description')
- self.description = _read_field('summary')
+ self.long_description = _read_field_unescaped_from_msg(msg, 'description')
+ self.description = _read_field_from_msg(msg, 'summary')
if 'keywords' in msg:
- self.keywords = _read_field('keywords').split(',')
+ self.keywords = _read_field_from_msg(msg, 'keywords').split(',')
- self.platforms = _read_list('platform')
- self.classifiers = _read_list('classifier')
+ self.platforms = _read_list_from_msg(msg, 'platform')
+ self.classifiers = _read_list_from_msg(msg, 'classifier')
# PEP 314 - these fields only exist in 1.1
if self.metadata_version == StrictVersion('1.1'):
- self.requires = _read_list('requires')
- self.provides = _read_list('provides')
- self.obsoletes = _read_list('obsoletes')
+ self.requires = _read_list_from_msg(msg, 'requires')
+ self.provides = _read_list_from_msg(msg, 'provides')
+ self.obsoletes = _read_list_from_msg(msg, 'obsoletes')
else:
self.requires = None
self.provides = None
diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py
index e4bba47b..dcec1734 100644
--- a/setuptools/tests/test_dist.py
+++ b/setuptools/tests/test_dist.py
@@ -10,6 +10,8 @@ from setuptools.dist import (
check_package_data,
DistDeprecationWarning,
check_specifier,
+ rfc822_escape,
+ rfc822_unescape,
)
from setuptools import sic
from setuptools import Distribution
@@ -85,6 +87,9 @@ def __read_test_cases():
('Metadata version 1.1: Provides', params(
provides=['package'],
)),
+ ('Metadata Version 1.0: Short long description', params(
+ long_description='Short long description',
+ )),
('Metadata version 1.1: Obsoletes', params(
obsoletes=['foo'],
)),
@@ -162,6 +167,7 @@ def test_read_metadata(name, attrs):
('metadata_version', dist_class.get_metadata_version),
('provides', dist_class.get_provides),
('description', dist_class.get_description),
+ ('long_description', dist_class.get_long_description),
('download_url', dist_class.get_download_url),
('keywords', dist_class.get_keywords),
('platforms', dist_class.get_platforms),
@@ -336,3 +342,37 @@ def test_check_specifier():
attrs = {'name': 'foo', 'python_requires': ['>=3.0', '!=3.1']}
with pytest.raises(DistutilsSetupError):
dist = Distribution(attrs)
+
+
+@pytest.mark.parametrize(
+ 'content, result',
+ (
+ pytest.param(
+ "Just a single line",
+ None,
+ id="single_line",
+ ),
+ pytest.param(
+ "Multiline\nText\nwithout\nextra indents\n",
+ None,
+ id="multiline",
+ ),
+ pytest.param(
+ "Multiline\n With\n\nadditional\n indentation",
+ None,
+ id="multiline_with_indentation",
+ ),
+ pytest.param(
+ " Leading whitespace",
+ "Leading whitespace",
+ id="remove_leading_whitespace",
+ ),
+ pytest.param(
+ " Leading whitespace\nIn\n Multiline comment",
+ "Leading whitespace\nIn\n Multiline comment",
+ id="remove_leading_whitespace_multiline",
+ ),
+ )
+)
+def test_rfc822_unescape(content, result):
+ assert (result or content) == rfc822_unescape(rfc822_escape(content))