Skip to content

Commit

Permalink
python-poetry#1350 - Improvements to handling of License file(s)
Browse files Browse the repository at this point in the history
- Fixes python-poetry#1350
- Added support for specifying a set of license files as part of the project config.
- Moved the license file config into the package configuration. (`Poetry.create()`) this matches how similar configurations such as “readme” are configured.
- Updated the builders to use the project level license file list instead of searching for their own (previously different) lists of license files.
- Moved the existing auto-discovery behaviours to become the default case during `create()` if nothing specific was configured.
- Added tests for the new features
- Documented the new configuration field.
- Added the “license-files” field to the poetry-schema.json
- Updated pre-commit config to use the correct black source repo.
- Fix python-poetry#866 by modifing the base template used by `SdistBuilder`. It now uses `setuptools`, since as documented by @seifertm in issue python-poetry#866 `pip` uses `setuptools` anyway and this clears the way to immediately supporting pypa/setuptools#1767 once this is merged and released from `setuptools`. Until `setuptools` updates to support multiple license files, this will result in a single log line in the debug output from `setuptools` so this is ok to merge before the change to `setuptools` is merged.
  • Loading branch information
Samuel Bishop committed Sep 12, 2019
1 parent 25f02c5 commit 5e71017
Show file tree
Hide file tree
Showing 24 changed files with 278 additions and 8 deletions.
5 changes: 3 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
default_language_version:
python: python3.6
repos:
- repo: https://github.com/ambv/black
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
python_version: python3.6
6 changes: 6 additions & 0 deletions docs/docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ The recommended notation for the most common licenses is (alphabetical):
Optional, but it is highly recommended to supply this.
More identifiers are listed at the [SPDX Open Source License Registry](https://www.spdx.org/licenses/).

## license-files

The license file(s) belonging to this package. **optional**

Poetry will automatically include files matching `LICENSE*` and `COPYING*` but if you have licenses files that do not fit these patterns, you can configure `poetry` to include one or more files as the license files. These paths should be relative to the project root directory, where the `pyproject.toml` lives.

## authors

The authors of the package. **Required**
Expand Down
10 changes: 10 additions & 0 deletions poetry/json/schemas/poetry-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"type": "string",
"description": "License name."
},
"license-files": {
"$ref": "#/definitions/license-files"
},
"authors": {
"$ref": "#/definitions/authors"
},
Expand Down Expand Up @@ -183,6 +186,13 @@
"type": "string"
}
},
"license-files": {
"type": "array",
"description": "A list of license files applicable to this packages. This accepts multiple files for situations involving more complicated licensing situations.",
"items": {
"type": "string"
}
},
"maintainers": {
"type": "array",
"description": "List of maintainers, other than the original author(s), that upkeep the package.",
Expand Down
5 changes: 3 additions & 2 deletions poetry/masonry/builders/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@ def find_files_to_add(self, exclude_build=True): # type: (bool) -> list
)
to_add.append(Path("pyproject.toml"))

# If a license file exists, add it
for license_file in self._path.glob("LICENSE*"):
# If any license files exist, add them.
for license_filename in self._package.license_files:
license_file = self._path / license_filename
self._io.write_line(
" - Adding: <comment>{}</comment>".format(
license_file.relative_to(self._path)
Expand Down
8 changes: 7 additions & 1 deletion poetry/masonry/builders/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

SETUP = """\
# -*- coding: utf-8 -*-
from distutils.core import setup
from setuptools import setup
{before}
setup_kwargs = {{
Expand Down Expand Up @@ -137,6 +137,12 @@ def build_setup(self): # type: () -> bytes
else:
pass

license_file_list = list(self._package.license_files)
if len(license_file_list) == 1:
extra.append("'license_file': \"{}\",".format(license_file_list[0]))
elif len(license_file_list) > 1:
extra.append("'license_file': \"{}\",".format(list(map(str, license_file_list))))

if package_dir:
before.append("package_dir = \\\n{}\n".format(pformat(package_dir)))
extra.append("'package_dir': package_dir,")
Expand Down
6 changes: 3 additions & 3 deletions poetry/masonry/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ def _write_metadata(self, wheel):
with self._write_to_zip(wheel, self.dist_info + "/entry_points.txt") as f:
self._write_entry_points(f)

for base in ("COPYING", "LICENSE"):
for path in sorted(self._path.glob(base + "*")):
self._add_file(wheel, path, "%s/%s" % (self.dist_info, path.name))
for license_file_name in self._package.license_files:
license_file = self._path / license_file_name
self._add_file(wheel, license_file, "%s/%s" % (self.dist_info, license_file.name))

with self._write_to_zip(wheel, self.dist_info + "/WHEEL") as f:
self._write_wheel_file(f)
Expand Down
1 change: 1 addition & 0 deletions poetry/packages/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def __init__(self, name, version, pretty_version=None):
self.documentation_url = None
self.keywords = []
self._license = None
self.license_files = set()
self.readme = None

self.source_name = ""
Expand Down
10 changes: 10 additions & 0 deletions poetry/poetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ def create(cls, cwd): # type: (Path) -> Poetry
if "readme" in local_config:
package.readme = Path(poetry_file.parent) / local_config["readme"]

# Add any manually defined or automatically discovered license files.
if "license-files" in local_config:
for file in local_config["license-files"]:
package.license_files.add(Path(poetry_file.parent) / file)
else:
for license_file in poetry_file.parent.glob("LICENSE*"):
package.license_files.add(license_file.relative_to(poetry_file.parent))
for license_file in poetry_file.parent.glob("COPYING*"):
package.license_files.add(license_file.relative_to(poetry_file.parent))

if "platform" in local_config:
package.platform = local_config["platform"]

Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Module 1
========
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[tool.poetry]
name = "the-package"
version = "4.5.6"
description = "Some description."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
license-files = [
"the-first-license.txt",
"the-second-license.txt"
]


readme = "README.rst"


[tool.poetry.dependencies]
python = "3.6"
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2018 Sébastien Eustace

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2018 Sébastien Eustace

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Example module"""

__version__ = "0.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Module 1
========
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[tool.poetry]
name = "the-package"
version = "4.5.6"
description = "Some description."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
license-files = [
"the-license.txt"
]

readme = "README.rst"


[tool.poetry.dependencies]
python = "3.6"
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2018 Sébastien Eustace

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Example module"""

__version__ = "0.1"
20 changes: 20 additions & 0 deletions tests/masonry/builders/fixtures/multiple-licenses/COPYING.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2018 Sébastien Eustace

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 changes: 20 additions & 0 deletions tests/masonry/builders/fixtures/multiple-licenses/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2018 Sébastien Eustace

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2 changes: 2 additions & 0 deletions tests/masonry/builders/fixtures/multiple-licenses/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Module 1
========
13 changes: 13 additions & 0 deletions tests/masonry/builders/fixtures/multiple-licenses/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[tool.poetry]
name = "the-package"
version = "4.5.6"
description = "Some description."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]

readme = "README.rst"


[tool.poetry.dependencies]
python = "3.6"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""Example module"""

__version__ = "4.5.6"
73 changes: 73 additions & 0 deletions tests/masonry/builders/test_complete.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,79 @@ def test_package_src():
zip.close()


def test_multiple_licenses():
module_path = fixtures_dir / "multiple-licenses"
builder = CompleteBuilder(
Poetry.create(module_path), NullEnv(execute=True), NullIO()
)
builder.build()

sdist = module_path / "dist" / "the-package-4.5.6.tar.gz"
wheel = module_path / "dist" / "the_package-4.5.6-py3-none-any.whl"

assert sdist.exists()
with tarfile.open(str(sdist), "r") as tar:
names = tar.getnames()
assert len(names) == len(set(names))
assert "the-package-4.5.6/LICENSE.txt" in names
assert "the-package-4.5.6/COPYING.txt" in names

assert wheel.exists()
with zipfile.ZipFile(str(wheel)) as z:
names = z.namelist()
assert len(names) == len(set(names))
assert "the_package-4.5.6.dist-info/LICENSE.txt" in names
assert "the_package-4.5.6.dist-info/COPYING.txt" in names


def test_explicit_license_config_single_license():
module_path = fixtures_dir / "explicit-license-config-single-license"
builder = CompleteBuilder(
Poetry.create(module_path), NullEnv(execute=True), NullIO()
)
builder.build()

sdist = module_path / "dist" / "the-package-4.5.6.tar.gz"
wheel = module_path / "dist" / "the_package-4.5.6-py3-none-any.whl"

assert sdist.exists()
with tarfile.open(str(sdist), "r") as tar:
names = tar.getnames()
assert len(names) == len(set(names))
assert "the-package-4.5.6/the-license.txt" in names

assert wheel.exists()
with zipfile.ZipFile(str(wheel)) as z:
names = z.namelist()
assert len(names) == len(set(names))
assert "the_package-4.5.6.dist-info/the-license.txt" in names


def test_explicit_license_config_multiple_licenses():
module_path = fixtures_dir / "explicit-license-config-multiple-licenses"
builder = CompleteBuilder(
Poetry.create(module_path), NullEnv(execute=True), NullIO()
)
builder.build()

sdist = module_path / "dist" / "the-package-4.5.6.tar.gz"
wheel = module_path / "dist" / "the_package-4.5.6-py3-none-any.whl"

assert sdist.exists()
with tarfile.open(str(sdist), "r") as tar:
names = tar.getnames()
assert len(names) == len(set(names))
assert "the-package-4.5.6/the-first-license.txt" in names
assert "the-package-4.5.6/the-second-license.txt" in names

assert wheel.exists()
with zipfile.ZipFile(str(wheel)) as z:
names = z.namelist()
assert len(names) == len(set(names))
assert "the_package-4.5.6.dist-info/the-first-license.txt" in names
assert "the_package-4.5.6.dist-info/the-second-license.txt" in names


def test_package_with_include(mocker):
module_path = fixtures_dir / "with-include"

Expand Down

0 comments on commit 5e71017

Please sign in to comment.