Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow files for license inputs #1559

Merged
merged 5 commits into from
Dec 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1551.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
File inputs for the `license` field in `setup.cfg` files now explicitly raise an error.
2 changes: 1 addition & 1 deletion docs/setuptools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,3 @@ universal = 1
license_file = LICENSE

[bumpversion:file:setup.py]

22 changes: 20 additions & 2 deletions setuptools/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,24 @@ def _parse_bool(cls, value):
value = value.lower()
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
Expand All @@ -255,7 +273,6 @@ def _parse_file(cls, value):
directory with setup.py.

Examples:
file: LICENSE
file: README.rst, CHANGELOG.md, src/file.txt

:param str value:
Expand Down Expand Up @@ -449,6 +466,7 @@ def parsers(self):
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,
Expand All @@ -460,7 +478,7 @@ def parsers(self):
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,
Expand Down
20 changes: 20 additions & 0 deletions setuptools/tests/test_config.py
Original file line number Diff line number Diff line change
@@ -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."""
Expand Down Expand Up @@ -146,6 +148,24 @@ def test_basic(self, tmpdir):
assert metadata.download_url == 'http://test.test.com/test/'
assert metadata.maintainer_email == '[email protected]'

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(
Expand Down
35 changes: 33 additions & 2 deletions setuptools/tests/test_egg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,37 @@ def test_expected_files_produced(self, tmpdir_cwd, env):
]
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()
Expand Down Expand Up @@ -597,8 +628,8 @@ def _run_egg_info_command(self, tmpdir_cwd, env, cmd=None, output=None):
data_stream=1,
env=environ,
)
if code:
raise AssertionError(data)
assert not code, data

if output:
assert output in data

Expand Down