Skip to content

Commit

Permalink
Merge pull request pypa#1559 from RajdeepRao/BUG-1551
Browse files Browse the repository at this point in the history
Disallow files for license inputs
  • Loading branch information
pganssle authored Dec 31, 2018
2 parents 0c9624f + 3db95bc commit f5c04b1
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 6 deletions.
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

0 comments on commit f5c04b1

Please sign in to comment.