aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--changelog.d/1551.breaking.rst1
-rw-r--r--docs/setuptools.txt2
-rw-r--r--setup.cfg1
-rw-r--r--setuptools/command/upload.py4
-rw-r--r--setuptools/config.py22
-rw-r--r--setuptools/tests/test_config.py20
-rw-r--r--setuptools/tests/test_egg_info.py35
7 files changed, 77 insertions, 8 deletions
diff --git a/changelog.d/1551.breaking.rst b/changelog.d/1551.breaking.rst
new file mode 100644
index 00000000..c0e477ce
--- /dev/null
+++ b/changelog.d/1551.breaking.rst
@@ -0,0 +1 @@
+File inputs for the `license` field in `setup.cfg` files now explicitly raise an error.
diff --git a/docs/setuptools.txt b/docs/setuptools.txt
index 81b850c3..cf166e9c 100644
--- a/docs/setuptools.txt
+++ b/docs/setuptools.txt
@@ -2370,7 +2370,7 @@ author_email author-email str
maintainer str
maintainer_email maintainer-email str
classifiers classifier file:, list-comma
-license file:, str
+license str
description summary file:, str
long_description long-description file:, str
long_description_content_type str 38.6.0
diff --git a/setup.cfg b/setup.cfg
index 57ab6234..dd404469 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -26,4 +26,3 @@ universal = 1
license_file = LICENSE
[bumpversion:file:setup.py]
-
diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py
index dd17f7a9..6db8888b 100644
--- a/setuptools/command/upload.py
+++ b/setuptools/command/upload.py
@@ -2,7 +2,6 @@ import io
import os
import hashlib
import getpass
-import platform
from base64 import standard_b64encode
@@ -16,6 +15,7 @@ from setuptools.extern.six.moves.urllib.request import urlopen, Request
from setuptools.extern.six.moves.urllib.error import HTTPError
from setuptools.extern.six.moves.urllib.parse import urlparse
+
class upload(orig.upload):
"""
Override default upload behavior to obtain password
@@ -80,7 +80,7 @@ class upload(orig.upload):
'version': meta.get_version(),
# file content
- 'content': (os.path.basename(filename),content),
+ 'content': (os.path.basename(filename), content),
'filetype': command,
'pyversion': pyversion,
'md5_digest': hashlib.md5(content).hexdigest(),
diff --git a/setuptools/config.py b/setuptools/config.py
index 9af72f25..59bb7708 100644
--- a/setuptools/config.py
+++ b/setuptools/config.py
@@ -247,6 +247,24 @@ class ConfigHandler:
return value in ('1', 'true', 'yes')
@classmethod
+ def _exclude_files_parser(cls, key):
+ """Returns a parser function to make sure field inputs
+ are not files.
+
+ Parses a value after getting the key so error messages are
+ more informative.
+
+ :param key:
+ :rtype: callable
+ """
+ def parser(value):
+ exclude_directive = 'file:'
+ if value.startswith(exclude_directive):
+ raise ValueError('Only strings are accepted for the {0} field, files are not accepted'.format(key))
+ return value
+ return parser
+
+ @classmethod
def _parse_file(cls, value):
"""Represents value as a string, allowing including text
from nearest files using `file:` directive.
@@ -255,7 +273,6 @@ class ConfigHandler:
directory with setup.py.
Examples:
- file: LICENSE
file: README.rst, CHANGELOG.md, src/file.txt
:param str value:
@@ -449,6 +466,7 @@ class ConfigMetadataHandler(ConfigHandler):
parse_list = self._parse_list
parse_file = self._parse_file
parse_dict = self._parse_dict
+ exclude_files_parser = self._exclude_files_parser
return {
'platforms': parse_list,
@@ -460,7 +478,7 @@ class ConfigMetadataHandler(ConfigHandler):
DeprecationWarning),
'obsoletes': parse_list,
'classifiers': self._get_parser_compound(parse_file, parse_list),
- 'license': parse_file,
+ 'license': exclude_files_parser('license'),
'description': parse_file,
'long_description': parse_file,
'version': self._parse_version,
diff --git a/setuptools/tests/test_config.py b/setuptools/tests/test_config.py
index 736c184d..53b8a956 100644
--- a/setuptools/tests/test_config.py
+++ b/setuptools/tests/test_config.py
@@ -1,10 +1,12 @@
import contextlib
import pytest
+
from distutils.errors import DistutilsOptionError, DistutilsFileError
from mock import patch
from setuptools.dist import Distribution, _Distribution
from setuptools.config import ConfigHandler, read_configuration
from . import py2_only, py3_only
+from .textwrap import DALS
class ErrConfigHandler(ConfigHandler):
"""Erroneous handler. Fails to implement required methods."""
@@ -146,6 +148,24 @@ class TestMetadata:
assert metadata.download_url == 'http://test.test.com/test/'
assert metadata.maintainer_email == 'test@test.com'
+ def test_license_cfg(self, tmpdir):
+ fake_env(
+ tmpdir,
+ DALS("""
+ [metadata]
+ name=foo
+ version=0.0.1
+ license=Apache 2.0
+ """)
+ )
+
+ with get_dist(tmpdir) as dist:
+ metadata = dist.metadata
+
+ assert metadata.name == "foo"
+ assert metadata.version == "0.0.1"
+ assert metadata.license == "Apache 2.0"
+
def test_file_mixed(self, tmpdir):
fake_env(
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
index f97b3f1d..979ff18e 100644
--- a/setuptools/tests/test_egg_info.py
+++ b/setuptools/tests/test_egg_info.py
@@ -148,6 +148,37 @@ class TestEggInfo:
]
assert sorted(actual) == expected
+ def test_license_is_a_string(self, tmpdir_cwd, env):
+ setup_config = DALS("""
+ [metadata]
+ name=foo
+ version=0.0.1
+ license=file:MIT
+ """)
+
+ setup_script = DALS("""
+ from setuptools import setup
+
+ setup()
+ """)
+
+ build_files({'setup.py': setup_script,
+ 'setup.cfg': setup_config})
+
+ # This command should fail with a ValueError, but because it's
+ # currently configured to use a subprocess, the actual traceback
+ # object is lost and we need to parse it from stderr
+ with pytest.raises(AssertionError) as exc:
+ self._run_egg_info_command(tmpdir_cwd, env)
+
+ # Hopefully this is not too fragile: the only argument to the
+ # assertion error should be a traceback, ending with:
+ # ValueError: ....
+ #
+ # assert not 1
+ tb = exc.value.args[0].split('\n')
+ assert tb[-3].lstrip().startswith('ValueError')
+
def test_rebuilt(self, tmpdir_cwd, env):
"""Ensure timestamps are updated when the command is re-run."""
self._create_project()
@@ -597,8 +628,8 @@ class TestEggInfo:
data_stream=1,
env=environ,
)
- if code:
- raise AssertionError(data)
+ assert not code, data
+
if output:
assert output in data