summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bumpversion.cfg2
-rw-r--r--CHANGES.rst13
-rw-r--r--docs/userguide/quickstart.rst9
-rw-r--r--setup.cfg2
-rw-r--r--setuptools/dist.py53
-rw-r--r--setuptools/tests/test_dist.py10
-rw-r--r--setuptools/tests/test_egg_info.py57
-rw-r--r--tools/finalize.py12
8 files changed, 106 insertions, 52 deletions
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 7b7bed92..036117a5 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 56.1.0
+current_version = 56.2.0
commit = True
tag = True
diff --git a/CHANGES.rst b/CHANGES.rst
index 13e936e0..f7dd6a75 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,4 +1,15 @@
-v56.1.0v56.1.0
+v56.2.0
+-------
+
+
+Changes
+^^^^^^^
+* #2640: Fixed handling of multiline license strings. - by :user:`cdce8p`
+* #2641: Setuptools will now always try to use the latest supported
+ metadata version for ``PKG-INFO``. - by :user:`cdce8p`
+
+
+v56.1.0
-------
diff --git a/docs/userguide/quickstart.rst b/docs/userguide/quickstart.rst
index 2807f59b..a9f0bbae 100644
--- a/docs/userguide/quickstart.rst
+++ b/docs/userguide/quickstart.rst
@@ -22,7 +22,7 @@ be generated with whatever tools that provides a ``build sdist``-alike
functionality. While this may appear cumbersome, given the added pieces,
it in fact tremendously enhances the portability of your package. The
change is driven under :pep:`PEP 517 <517#build-requirements>`. To learn more about Python packaging in general,
-navigate to the `bottom <Resources on python packaging>`_ of this page.
+navigate to the :ref:`bottom <packaging-resources>` of this page.
Basic Use
@@ -52,8 +52,8 @@ the minimum
[options]
packages = mypackage
install_requires =
- requests
- importlib; python_version == "2.6"
+ requests
+ importlib; python_version == "2.6"
.. tab:: setup.py
@@ -215,13 +215,14 @@ basic use here.
Transitioning from ``setup.py`` to ``setup.cfg``
-==================================================
+================================================
To avoid executing arbitary scripts and boilerplate code, we are transitioning
into a full-fledged ``setup.cfg`` to declare your package information instead
of running ``setup()``. This inevitably brings challenges due to a different
syntax. Here we provide a quick guide to understanding how ``setup.cfg`` is
parsed by ``setuptool`` to ease the pain of transition.
+.. _packaging-resources:
Resources on Python packaging
=============================
diff --git a/setup.cfg b/setup.cfg
index ab927a31..2ecba4b3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -2,7 +2,7 @@
license_files =
LICENSE
name = setuptools
-version = 56.1.0
+version = 56.2.0
author = Python Packaging Authority
author_email = distutils-sig@python.org
description = Easily download, build, install, upgrade, and uninstall Python packages
diff --git a/setuptools/dist.py b/setuptools/dist.py
index c7af35dc..24aef1bb 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -52,23 +52,9 @@ def _get_unpatched(cls):
def get_metadata_version(self):
mv = getattr(self, 'metadata_version', None)
-
if mv is None:
- if self.long_description_content_type or self.provides_extras:
- mv = StrictVersion('2.1')
- elif (self.maintainer is not None or
- self.maintainer_email is not None or
- getattr(self, 'python_requires', None) is not None or
- self.project_urls):
- mv = StrictVersion('1.2')
- elif (self.provides or self.requires or self.obsoletes or
- self.classifiers or self.download_url):
- mv = StrictVersion('1.1')
- else:
- mv = StrictVersion('1.0')
-
+ mv = StrictVersion('2.1')
self.metadata_version = mv
-
return mv
@@ -120,7 +106,7 @@ def read_pkg_file(self, file):
self.author_email = _read_field_from_msg(msg, 'author-email')
self.maintainer_email = None
self.url = _read_field_from_msg(msg, 'home-page')
- self.license = _read_field_from_msg(msg, 'license')
+ self.license = _read_field_unescaped_from_msg(msg, 'license')
if 'download-url' in msg:
self.download_url = _read_field_from_msg(msg, 'download-url')
@@ -171,24 +157,20 @@ def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME
write_field('Summary', single_line(self.get_description()))
write_field('Home-page', self.get_url())
- if version < StrictVersion('1.2'):
- write_field('Author', self.get_contact())
- write_field('Author-email', self.get_contact_email())
- else:
- optional_fields = (
- ('Author', 'author'),
- ('Author-email', 'author_email'),
- ('Maintainer', 'maintainer'),
- ('Maintainer-email', 'maintainer_email'),
- )
+ optional_fields = (
+ ('Author', 'author'),
+ ('Author-email', 'author_email'),
+ ('Maintainer', 'maintainer'),
+ ('Maintainer-email', 'maintainer_email'),
+ )
- for field, attr in optional_fields:
- attr_val = getattr(self, attr)
+ for field, attr in optional_fields:
+ attr_val = getattr(self, attr, None)
+ if attr_val is not None:
+ write_field(field, attr_val)
- if attr_val is not None:
- write_field(field, attr_val)
-
- write_field('License', self.get_license())
+ license = rfc822_escape(self.get_license())
+ write_field('License', license)
if self.download_url:
write_field('Download-URL', self.download_url)
for project_url in self.project_urls.items():
@@ -201,11 +183,8 @@ def write_pkg_file(self, file): # noqa: C901 # is too complex (14) # FIXME
if keywords:
write_field('Keywords', keywords)
- if version >= StrictVersion('1.2'):
- for platform in self.get_platforms():
- write_field('Platform', platform)
- else:
- self._write_list(file, 'Platform', self.get_platforms())
+ for platform in self.get_platforms():
+ write_field('Platform', platform)
self._write_list(file, 'Classifier', self.get_classifiers())
diff --git a/setuptools/tests/test_dist.py b/setuptools/tests/test_dist.py
index dcec1734..6378caef 100644
--- a/setuptools/tests/test_dist.py
+++ b/setuptools/tests/test_dist.py
@@ -84,15 +84,9 @@ def __read_test_cases():
test_cases = [
('Metadata version 1.0', params()),
- ('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'],
- )),
('Metadata version 1.1: Classifiers', params(
classifiers=[
'Programming Language :: Python :: 3',
@@ -116,6 +110,10 @@ def __read_test_cases():
('Metadata Version 2.1: Long Description Content Type', params(
long_description_content_type='text/x-rst; charset=UTF-8',
)),
+ ('License', params(license='MIT', )),
+ ('License multiline', params(
+ license='This is a long license \nover multiple lines',
+ )),
pytest.param(
'Metadata Version 2.1: Provides Extra',
params(provides_extras=['foo', 'bar']),
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index 80d35774..0d595ad0 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -5,6 +5,7 @@ import glob
import re
import stat
import time
+from typing import List, Tuple
import pytest
from jaraco import path
@@ -45,6 +46,11 @@ class TestEggInfo:
""")
})
+ @staticmethod
+ def _extract_mv_version(pkg_info_lines: List[str]) -> Tuple[int, int]:
+ version_str = pkg_info_lines[0].split(' ')[1]
+ return tuple(map(int, version_str.split('.')[:2]))
+
@pytest.fixture
def env(self):
with contexts.tempdir(prefix='setuptools-test.') as env_dir:
@@ -829,6 +835,20 @@ class TestEggInfo:
for lf in excl_licenses:
assert sources_lines.count(lf) == 0
+ def test_metadata_version(self, tmpdir_cwd, env):
+ """Make sure latest metadata version is used by default."""
+ self._setup_script_with_requires("")
+ code, data = environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
+ data_stream=1,
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+ with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file:
+ pkg_info_lines = pkginfo_file.read().split('\n')
+ # Update metadata version if changed
+ assert self._extract_mv_version(pkg_info_lines) == (2, 1)
+
def test_long_description_content_type(self, tmpdir_cwd, env):
# Test that specifying a `long_description_content_type` keyword arg to
# the `setup` function results in writing a `Description-Content-Type`
@@ -884,7 +904,40 @@ class TestEggInfo:
assert expected_line in pkg_info_lines
expected_line = 'Project-URL: Link Two, https://example.com/two/'
assert expected_line in pkg_info_lines
- assert 'Metadata-Version: 1.2' in pkg_info_lines
+ assert self._extract_mv_version(pkg_info_lines) >= (1, 2)
+
+ def test_license(self, tmpdir_cwd, env):
+ """Test single line license."""
+ self._setup_script_with_requires(
+ "license='MIT',"
+ )
+ code, data = environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
+ data_stream=1,
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+ with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file:
+ pkg_info_lines = pkginfo_file.read().split('\n')
+ assert 'License: MIT' in pkg_info_lines
+
+ def test_license_escape(self, tmpdir_cwd, env):
+ """Test license is escaped correctly if longer than one line."""
+ self._setup_script_with_requires(
+ "license='This is a long license text \\nover multiple lines',"
+ )
+ code, data = environment.run_setup_py(
+ cmd=['egg_info'],
+ pypath=os.pathsep.join([env.paths['lib'], str(tmpdir_cwd)]),
+ data_stream=1,
+ )
+ egg_info_dir = os.path.join('.', 'foo.egg-info')
+ with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file:
+ pkg_info_lines = pkginfo_file.read().split('\n')
+
+ assert 'License: This is a long license text ' in pkg_info_lines
+ assert ' over multiple lines' in pkg_info_lines
+ assert 'text \n over multiple' in '\n'.join(pkg_info_lines)
def test_python_requires_egg_info(self, tmpdir_cwd, env):
self._setup_script_with_requires(
@@ -902,7 +955,7 @@ class TestEggInfo:
with open(os.path.join(egg_info_dir, 'PKG-INFO')) as pkginfo_file:
pkg_info_lines = pkginfo_file.read().split('\n')
assert 'Requires-Python: >=2.7.12' in pkg_info_lines
- assert 'Metadata-Version: 1.2' in pkg_info_lines
+ assert self._extract_mv_version(pkg_info_lines) >= (1, 2)
def test_manifest_maker_warning_suppression(self):
fixtures = [
diff --git a/tools/finalize.py b/tools/finalize.py
index 35294281..516a2fb5 100644
--- a/tools/finalize.py
+++ b/tools/finalize.py
@@ -46,6 +46,18 @@ def update_changelog():
'--yes',
]
subprocess.check_call(cmd)
+ _repair_changelog()
+
+
+def _repair_changelog():
+ """
+ Workaround for #2666
+ """
+ changelog_fn = pathlib.Path('CHANGES.rst')
+ changelog = changelog_fn.read_text()
+ fixed = re.sub(r'^(v[0-9.]+)v[0-9.]+$', r'\1', changelog, flags=re.M)
+ changelog_fn.write_text(fixed)
+ subprocess.check_output(['git', 'add', changelog_fn])
def bump_version():