Skip to content
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
23 changes: 13 additions & 10 deletions docs/libraries.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,19 @@ poetry build
This command will package your library in two different formats: `sdist` which is
the source format, and `wheel` which is a `compiled` package.

Poetry will automatically include some metadata files when building a package. When building
a `wheel`, the following files are included in the `.dist-info` directory:
- `LICENSE`
- `LICENSE.*`
- `COPYING`
- `COPYING.*`
- `LICENSES/**`

When building an `sdist`, the following files will be included in the root folder:
- `LICENSE*`
Poetry will automatically include some license-related files when building a package -
in the `.dist-info/licenses` directory when building a `wheel`,
and in the root folder when building an `sdist`:
- `LICENSE*`
- `LICENCE*`
- `COPYING*`
- `AUTHORS*`
- `NOTICE*`
- `LICENSES/**/*`

You can override this behavior by specifying
[`license-files`]({{< relref "pyproject/#license-files" >}})
in the `pyproject.toml` file.

### Alternative build backends

Expand Down
52 changes: 35 additions & 17 deletions docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ description = "A short description of the package."

### license

The license of the package.
An [SPDX expression](https://packaging.python.org/en/latest/glossary/#term-License-Expression)
representing the license of the package.

The recommended notation for the most common licenses is (alphabetical):

Expand All @@ -93,20 +94,43 @@ Optional, but it is highly recommended to supply this.
More identifiers are listed at the [SPDX Open Source License Registry](https://spdx.org/licenses/).

```toml
license = { text = "MIT" }
license = "MIT"
```
{{% note %}}
If your project is proprietary and does not use a specific license, you can set this value as `Proprietary`.
{{% /note %}}

You can also specify a license file. However, when doing this, the complete license text
will be added to the metadata and the License classifier cannot be determined
automatically so that you have to add it manually.
{{% warning %}}
Specifying license as a table, e.g. `{ text = "MIT" }` is deprecated.
If you used to specify a license file, e.g. `{ file = "LICENSE" }`,
use `license-files` instead.
{{% /warning %}}

### license-files

A list of glob patterns that match the license files of the package
relative to the root of the project source tree.

```toml
license = { file = "LICENSE" }
[project]
# ...
license-files = [
"*-LICENSE",
"CONTRIBUTORS",
"MY-SPECIAL-LICENSE-DIR/**/*"
]
```

By default, Poetry will include the following files:
- `LICENSE*`
- `LICENCE*`
- `COPYING*`
- `AUTHORS*`
- `NOTICE*`
- `LICENSES/**/*`

{{% note %}}
The default applies only if the `license-files` field is not specified.
Specifying an empty list results in no license files being included.
{{% /note %}}

### readme

A path to the README file or the content.
Expand Down Expand Up @@ -198,7 +222,7 @@ classifiers = [
```

{{% warning %}}
Note that suitable classifiers based on your `python` requirement and `license`
Note that suitable classifiers based on your `python` requirement
are **not** automatically added for you if you define classifiers statically
in the `project` section.

Expand Down Expand Up @@ -419,9 +443,6 @@ More identifiers are listed at the [SPDX Open Source License Registry](https://s
```toml
license = "MIT"
```
{{% note %}}
If your project is proprietary and does not use a specific licence, you can set this value as `Proprietary`.
{{% /note %}}

### authors

Expand Down Expand Up @@ -545,11 +566,8 @@ classifiers = [
Note that Python classifiers are automatically added for you
and are determined by your `python` requirement.

The `license` property will also set the License classifier automatically.

If you do not want Poetry to automatically add suitable classifiers
based on the `python` requirement and `license` property,
use `project.classifiers` instead of this setting.
based on the `python` requirement, use `project.classifiers` instead of this setting.
{{% /note %}}

### packages
Expand Down
4 changes: 2 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies = [
"installer (>=0.7.0,<0.8.0)",
"keyring (>=25.1.0,<26.0.0)",
# packaging uses calver, so version is unclamped
"packaging (>=24.0)",
"packaging (>=24.2)", # PEP 639 support was added in 24.2
"pkginfo (>=1.12,<2.0)",
"platformdirs (>=3.0.0,<5)",
"pyproject-hooks (>=1.0.0,<2.0.0)",
Expand Down Expand Up @@ -44,7 +44,7 @@ maintainers = [
{ name = "finswimmer", email = "[email protected]" },
{ name = "Bartosz Sokorski", email = "[email protected]" },
]
license = { text = "MIT" }
license = "MIT"
readme = "README.md"
keywords = ["packaging", "dependency", "poetry"]
# classifieres is dynamic because we want to create Python classifiers automatically
Expand Down
17 changes: 3 additions & 14 deletions src/poetry/masonry/builders/editable.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,6 @@ def _add_scripts(self) -> list[Path]:
def _add_dist_info(self, added_files: list[Path]) -> None:
from poetry.core.masonry.builders.wheel import WheelBuilder

added_files = added_files[:]

builder = WheelBuilder(self._poetry)
dist_info = self._env.site_packages.mkdir(Path(builder.dist_info))

Expand All @@ -226,24 +224,15 @@ def _add_dist_info(self, added_files: list[Path]) -> None:
f" <b>{dist_info.parent}</b>"
)

with dist_info.joinpath("METADATA").open("w", encoding="utf-8") as f:
builder._write_metadata_file(f)

added_files.append(dist_info.joinpath("METADATA"))
builder.prepare_metadata(dist_info.parent)
for path in sorted(f for f in dist_info.rglob("*") if f.is_file()):
added_files.append(path)

with dist_info.joinpath("INSTALLER").open("w", encoding="utf-8") as f:
f.write("poetry")

added_files.append(dist_info.joinpath("INSTALLER"))

if self.convert_entry_points():
with dist_info.joinpath("entry_points.txt").open(
"w", encoding="utf-8"
) as f:
builder._write_entry_points(f)

added_files.append(dist_info.joinpath("entry_points.txt"))

# write PEP 610 metadata
direct_url_json = dist_info.joinpath("direct_url.json")
direct_url_json.write_text(
Expand Down
2 changes: 2 additions & 0 deletions tests/console/commands/test_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ def test_check_invalid(
Error: Invalid source "not-exists" referenced in dependencies.
Error: Invalid source "not-exists2" referenced in dependencies.
Error: poetry.lock was not found.
Warning: [project.license] is not a valid SPDX identifier.\
This is deprecated and will raise an error in the future.
Warning: A wildcard Python dependency is ambiguous.\
Consider specifying a more explicit one.
Warning: The "pendulum" dependency specifies the "allows-prereleases" property,\
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/invalid_pyproject/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "invalid"
version = "1.0.0"
license = { text = "INVALID" }
license = "INVALID"
classifiers = [
"Environment :: Console",
"Intended Audience :: Clowns",
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/simple_project/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
license ...
2 changes: 1 addition & 1 deletion tests/fixtures/simple_project/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Some description."
authors = [
{ name = "Sébastien Eustace", email = "[email protected]" }
]
license = { text = "MIT" }
license = "MIT"
readme = "README.rst"
keywords = ["packaging", "dependency", "poetry"]
dynamic = [ "classifiers", "dependencies", "requires-python" ]
Expand Down
1 change: 1 addition & 0 deletions tests/fixtures/simple_project_legacy/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
license ...
24 changes: 17 additions & 7 deletions tests/masonry/builders/test_editable_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,12 @@ def test_builder_installs_proper_files_for_standard_packages(

dist_info = tmp_venv.site_packages.find(dist_info)[0]

assert dist_info.joinpath("INSTALLER").exists()
assert dist_info.joinpath("entry_points.txt").exists()
assert dist_info.joinpath("WHEEL").exists()
assert dist_info.joinpath("METADATA").exists()
assert dist_info.joinpath("licenses/LICENSE").exists()
assert dist_info.joinpath("INSTALLER").exists()
assert dist_info.joinpath("RECORD").exists()
assert dist_info.joinpath("entry_points.txt").exists()
assert dist_info.joinpath("direct_url.json").exists()

assert not DeepDiff(
Expand Down Expand Up @@ -175,6 +177,7 @@ def test_builder_installs_proper_files_for_standard_packages(
Version: 1.2.3
Summary: Some description.
License: MIT
License-File: LICENSE
Keywords: packaging,dependency,poetry
Author: Sébastien Eustace
Author-email: [email protected]
Expand All @@ -192,7 +195,11 @@ def test_builder_installs_proper_files_for_standard_packages(
==========

"""
assert metadata == dist_info.joinpath("METADATA").read_text(encoding="utf-8")
if project == "simple_project":
metadata = metadata.replace("License:", "License-Expression:").replace(
"Classifier: License :: OSI Approved :: MIT License\n", ""
)
assert dist_info.joinpath("METADATA").read_text(encoding="utf-8") == metadata

with open(dist_info.joinpath("RECORD"), encoding="utf-8", newline="") as f:
reader = csv.reader(f)
Expand All @@ -205,9 +212,12 @@ def test_builder_installs_proper_files_for_standard_packages(
assert str(tmp_venv.site_packages.find(pth_file)[0]) in record_entries
assert str(tmp_venv._bin_dir.joinpath("foo")) in record_entries
assert str(tmp_venv._bin_dir.joinpath("baz")) in record_entries
assert str(dist_info.joinpath("entry_points.txt")) in record_entries
assert str(dist_info.joinpath("WHEEL")) in record_entries
assert str(dist_info.joinpath("METADATA")) in record_entries
assert str(dist_info.joinpath("licenses/LICENSE")) in record_entries

assert str(dist_info.joinpath("INSTALLER")) in record_entries
assert str(dist_info.joinpath("entry_points.txt")) in record_entries
assert str(dist_info.joinpath("RECORD")) in record_entries
assert str(dist_info.joinpath("direct_url.json")) in record_entries

Expand All @@ -220,7 +230,7 @@ def test_builder_installs_proper_files_for_standard_packages(
sys.exit(baz.boom.bim())
"""

assert baz_script == tmp_venv._bin_dir.joinpath("baz").read_text(encoding="utf-8")
assert tmp_venv._bin_dir.joinpath("baz").read_text(encoding="utf-8") == baz_script

foo_script = f"""\
#!{tmp_venv.python}
Expand All @@ -231,7 +241,7 @@ def test_builder_installs_proper_files_for_standard_packages(
sys.exit(bar())
"""

assert foo_script == tmp_venv._bin_dir.joinpath("foo").read_text(encoding="utf-8")
assert tmp_venv._bin_dir.joinpath("foo").read_text(encoding="utf-8") == foo_script

fox_script = f"""\
#!{tmp_venv.python}
Expand All @@ -242,7 +252,7 @@ def test_builder_installs_proper_files_for_standard_packages(
sys.exit(bar.baz())
"""

assert fox_script == tmp_venv._bin_dir.joinpath("fox").read_text(encoding="utf-8")
assert tmp_venv._bin_dir.joinpath("fox").read_text(encoding="utf-8") == fox_script


def test_builder_falls_back_on_setup_and_pip_for_packages_with_build_scripts(
Expand Down