mirror of
https://github.com/python/cpython.git
synced 2026-01-03 14:02:21 +00:00
bpo-19610: setup() now raises TypeError for invalid types (GH-4519)
The Distribution class now explicitly raises an exception when 'classifiers', 'keywords' and 'platforms' fields are not specified as a list.
This commit is contained in:
parent
6a54c676e6
commit
dcaed6b2d9
6 changed files with 112 additions and 12 deletions
|
|
@ -285,6 +285,10 @@ the full reference.
|
|||
See the :func:`setup` function for a list of keyword arguments accepted by the
|
||||
Distribution constructor. :func:`setup` creates a Distribution instance.
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
:class:`~distutils.core.Distribution` now raises a :exc:`TypeError` if
|
||||
``classifiers``, ``keywords`` and ``platforms`` fields are not specified
|
||||
as a list.
|
||||
|
||||
.. class:: Command
|
||||
|
||||
|
|
|
|||
|
|
@ -581,17 +581,19 @@ This information includes:
|
|||
| | description of the | | |
|
||||
| | package | | |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
| ``long_description`` | longer description of the | long string | \(5) |
|
||||
| ``long_description`` | longer description of the | long string | \(4) |
|
||||
| | package | | |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
| ``download_url`` | location where the | URL | \(4) |
|
||||
| ``download_url`` | location where the | URL | |
|
||||
| | package may be downloaded | | |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
| ``classifiers`` | a list of classifiers | list of strings | \(4) |
|
||||
| ``classifiers`` | a list of classifiers | list of strings | (6)(7) |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
| ``platforms`` | a list of platforms | list of strings | |
|
||||
| ``platforms`` | a list of platforms | list of strings | (6)(8) |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
| ``license`` | license for the package | short string | \(6) |
|
||||
| ``keywords`` | a list of keywords | list of strings | (6)(8) |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
| ``license`` | license for the package | short string | \(5) |
|
||||
+----------------------+---------------------------+-----------------+--------+
|
||||
|
||||
Notes:
|
||||
|
|
@ -607,22 +609,30 @@ Notes:
|
|||
provided, distutils lists it as the author in :file:`PKG-INFO`.
|
||||
|
||||
(4)
|
||||
These fields should not be used if your package is to be compatible with Python
|
||||
versions prior to 2.2.3 or 2.3. The list is available from the `PyPI website
|
||||
<https://pypi.python.org/pypi>`_.
|
||||
|
||||
(5)
|
||||
The ``long_description`` field is used by PyPI when you are
|
||||
:ref:`registering <package-register>` a package, to
|
||||
:ref:`build its home page <package-display>`.
|
||||
|
||||
(6)
|
||||
(5)
|
||||
The ``license`` field is a text indicating the license covering the
|
||||
package where the license is not a selection from the "License" Trove
|
||||
classifiers. See the ``Classifier`` field. Notice that
|
||||
there's a ``licence`` distribution option which is deprecated but still
|
||||
acts as an alias for ``license``.
|
||||
|
||||
(6)
|
||||
This field must be a list.
|
||||
|
||||
(7)
|
||||
The valid classifiers are listed on
|
||||
`PyPI <http://pypi.python.org/pypi?:action=list_classifiers>`_.
|
||||
|
||||
(8)
|
||||
To preserve backward compatibility, this field also accepts a string. If
|
||||
you pass a comma-separated string ``'foo, bar'``, it will be converted to
|
||||
``['foo', 'bar']``, Otherwise, it will be converted to a list of one
|
||||
string.
|
||||
|
||||
'short string'
|
||||
A single line of text, not more than 200 characters.
|
||||
|
||||
|
|
@ -650,7 +660,7 @@ information is sometimes used to indicate sub-releases. These are
|
|||
1.0.1a2
|
||||
the second alpha release of the first patch version of 1.0
|
||||
|
||||
``classifiers`` are specified in a Python list::
|
||||
``classifiers`` must be specified in a list::
|
||||
|
||||
setup(...,
|
||||
classifiers=[
|
||||
|
|
@ -671,6 +681,11 @@ information is sometimes used to indicate sub-releases. These are
|
|||
],
|
||||
)
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
:class:`~distutils.core.setup` now raises a :exc:`TypeError` if
|
||||
``classifiers``, ``keywords`` and ``platforms`` fields are not specified
|
||||
as a list.
|
||||
|
||||
.. _debug-setup-script:
|
||||
|
||||
Debugging the setup script
|
||||
|
|
|
|||
|
|
@ -298,6 +298,12 @@ README.rst is now included in the list of distutils standard READMEs and
|
|||
therefore included in source distributions.
|
||||
(Contributed by Ryan Gonzalez in :issue:`11913`.)
|
||||
|
||||
:class:`distutils.core.setup` now raises a :exc:`TypeError` if
|
||||
``classifiers``, ``keywords`` and ``platforms`` fields are not specified
|
||||
as a list. However, to minimize backwards incompatibility concerns,
|
||||
``keywords`` and ``platforms`` fields still accept a comma separated string.
|
||||
(Contributed by Berker Peksag in :issue:`19610`.)
|
||||
|
||||
http.client
|
||||
-----------
|
||||
|
||||
|
|
|
|||
|
|
@ -1188,12 +1188,38 @@ def get_long_description(self):
|
|||
def get_keywords(self):
|
||||
return self.keywords or []
|
||||
|
||||
def set_keywords(self, value):
|
||||
# If 'keywords' is a string, it will be converted to a list
|
||||
# by Distribution.finalize_options(). To maintain backwards
|
||||
# compatibility, do not raise an exception if 'keywords' is
|
||||
# a string.
|
||||
if not isinstance(value, (list, str)):
|
||||
msg = "'keywords' should be a 'list', not %r"
|
||||
raise TypeError(msg % type(value).__name__)
|
||||
self.keywords = value
|
||||
|
||||
def get_platforms(self):
|
||||
return self.platforms or ["UNKNOWN"]
|
||||
|
||||
def set_platforms(self, value):
|
||||
# If 'platforms' is a string, it will be converted to a list
|
||||
# by Distribution.finalize_options(). To maintain backwards
|
||||
# compatibility, do not raise an exception if 'platforms' is
|
||||
# a string.
|
||||
if not isinstance(value, (list, str)):
|
||||
msg = "'platforms' should be a 'list', not %r"
|
||||
raise TypeError(msg % type(value).__name__)
|
||||
self.platforms = value
|
||||
|
||||
def get_classifiers(self):
|
||||
return self.classifiers or []
|
||||
|
||||
def set_classifiers(self, value):
|
||||
if not isinstance(value, list):
|
||||
msg = "'classifiers' should be a 'list', not %r"
|
||||
raise TypeError(msg % type(value).__name__)
|
||||
self.classifiers = value
|
||||
|
||||
def get_download_url(self):
|
||||
return self.download_url or "UNKNOWN"
|
||||
|
||||
|
|
|
|||
|
|
@ -195,6 +195,13 @@ def test_finalize_options(self):
|
|||
self.assertEqual(dist.metadata.platforms, ['one', 'two'])
|
||||
self.assertEqual(dist.metadata.keywords, ['one', 'two'])
|
||||
|
||||
attrs = {'keywords': 'foo bar',
|
||||
'platforms': 'foo bar'}
|
||||
dist = Distribution(attrs=attrs)
|
||||
dist.finalize_options()
|
||||
self.assertEqual(dist.metadata.platforms, ['foo bar'])
|
||||
self.assertEqual(dist.metadata.keywords, ['foo bar'])
|
||||
|
||||
def test_get_command_packages(self):
|
||||
dist = Distribution()
|
||||
self.assertEqual(dist.command_packages, None)
|
||||
|
|
@ -338,9 +345,46 @@ def test_classifier(self):
|
|||
attrs = {'name': 'Boa', 'version': '3.0',
|
||||
'classifiers': ['Programming Language :: Python :: 3']}
|
||||
dist = Distribution(attrs)
|
||||
self.assertEqual(dist.get_classifiers(),
|
||||
['Programming Language :: Python :: 3'])
|
||||
meta = self.format_metadata(dist)
|
||||
self.assertIn('Metadata-Version: 1.1', meta)
|
||||
|
||||
def test_classifier_invalid_type(self):
|
||||
attrs = {'name': 'Boa', 'version': '3.0',
|
||||
'classifiers': ('Programming Language :: Python :: 3',)}
|
||||
msg = "'classifiers' should be a 'list', not 'tuple'"
|
||||
with self.assertRaises(TypeError, msg=msg):
|
||||
Distribution(attrs)
|
||||
|
||||
def test_keywords(self):
|
||||
attrs = {'name': 'Monty', 'version': '1.0',
|
||||
'keywords': ['spam', 'eggs', 'life of brian']}
|
||||
dist = Distribution(attrs)
|
||||
self.assertEqual(dist.get_keywords(),
|
||||
['spam', 'eggs', 'life of brian'])
|
||||
|
||||
def test_keywords_invalid_type(self):
|
||||
attrs = {'name': 'Monty', 'version': '1.0',
|
||||
'keywords': ('spam', 'eggs', 'life of brian')}
|
||||
msg = "'keywords' should be a 'list', not 'tuple'"
|
||||
with self.assertRaises(TypeError, msg=msg):
|
||||
Distribution(attrs)
|
||||
|
||||
def test_platforms(self):
|
||||
attrs = {'name': 'Monty', 'version': '1.0',
|
||||
'platforms': ['GNU/Linux', 'Some Evil Platform']}
|
||||
dist = Distribution(attrs)
|
||||
self.assertEqual(dist.get_platforms(),
|
||||
['GNU/Linux', 'Some Evil Platform'])
|
||||
|
||||
def test_platforms_invalid_types(self):
|
||||
attrs = {'name': 'Monty', 'version': '1.0',
|
||||
'platforms': ('GNU/Linux', 'Some Evil Platform')}
|
||||
msg = "'platforms' should be a 'list', not 'tuple'"
|
||||
with self.assertRaises(TypeError, msg=msg):
|
||||
Distribution(attrs)
|
||||
|
||||
def test_download_url(self):
|
||||
attrs = {'name': 'Boa', 'version': '3.0',
|
||||
'download_url': 'http://example.org/boa'}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
``setup()`` now raises :exc:`TypeError` for invalid types.
|
||||
|
||||
The ``distutils.dist.Distribution`` class now explicitly raises an exception
|
||||
when ``classifiers``, ``keywords`` and ``platforms`` fields are not
|
||||
specified as a list.
|
||||
Loading…
Add table
Add a link
Reference in a new issue