Skip to content

Commit 0d9b896

Browse files
Merge pull request #355 from plone/315-move-setup-py-to-pyproject-toml
Move setup.py metadata to pyproject.toml
2 parents 5b423ef + 34d4a2a commit 0d9b896

7 files changed

Lines changed: 830 additions & 1 deletion

File tree

docs/sources/how-to/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ Set up CI jobs, Python version matrices, OS dependencies, and environment variab
4545
Set up CI pipelines for GitLab-hosted repositories, including custom Docker images and OS dependencies.
4646
:::
4747

48+
:::{grid-item-card} Convert `setup.py` metadata to `pyproject.toml`
49+
:link: setup-to-pyproject
50+
:link-type: doc
51+
52+
Convert the metadata in `setup.py` to `pyproject.toml`
53+
:::
54+
4855
:::{grid-item-card} Re-enable GitHub Actions
4956
:link: re-enable-actions
5057
:link-type: doc
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Convert setup.py metadata to pyproject.toml
2+
3+
`pyproject.toml`'s `[project]` metadata is the standard place to find a project metadata.
4+
5+
Historically this was on `setup.py`, but it had plenty of problems.
6+
7+
Now, you can write all of a project's metadata in `pyproject.toml`,
8+
[see the specification](https://packaging.python.org/en/latest/specifications/pyproject-toml/).
9+
10+
All plone and collective python distributions are using `setup.py` to keep each project's metadata.
11+
12+
[`zope.meta`](https://pypi.org/project/zope.meta) created a script to move the metadata from `setup.py` to `pyproject.toml`.
13+
14+
In `plone.meta` this script from `zope.meta` has been adapted to suit the needs of the Plone ecosystem.
15+
16+
## Conversion
17+
18+
To convert the metadata do the following:
19+
20+
```bash
21+
cd $REPOSITORY
22+
uvx --from plone.meta setup-to-pyproject .
23+
```
24+
25+
i.e. go to your repository and run the `setup-to-pyproject` script from `plone.meta`.
26+
27+
This will automatically create a commit on your repository with the changes.
28+
29+
:::{note}
30+
Please review them carefully to ensure that the conversion was done properly.
31+
:::
32+
33+
Ideally `setup.py` should look like this:
34+
35+
```python
36+
from setuptools import setup
37+
38+
# See pyproject.toml for package metadata
39+
setup()
40+
```
41+
42+
### Issues link
43+
44+
`setup-to-pyproject` accepts an optional argument: `--issues`.
45+
46+
This option is to customize the issues link displayed on PyPI related to the project.
47+
48+
It accepts the following options:
49+
50+
- `own`: use the repository itself as the issue tracker
51+
- _URL_: provide a custom URL that will be used verbatim
52+
- _None_: if no value is provided `Products.CMFPlone` issue tracker is used
53+
54+
## Clean up
55+
56+
Run some tooling `tox run -e test` to ensure that the conversion worked.
57+
58+
:::{note}
59+
It might be that the license field in `project.license` within `pyproject.toml` is broken.
60+
61+
Please have a look at valid [license expressions](https://packaging.python.org/en/latest/specifications/license-expression/) to solve it.
62+
:::
63+
64+
Re-configure the repository with `plone.meta` to ensure that the project metadata is kept:
65+
66+
```bash
67+
cd $REPOSITORY
68+
uvx --from plone.meta config-package branch=current .
69+
```
70+
71+
Make sure to review the commit generated by `config-package`.

news/315.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `setup-to-pyproject` script to move `setup.py` metadata into `pyproject.toml` @gforcada

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ config-package = "plone.meta.config_package:main"
5858
multi-call = "plone.meta.multi_call:main"
5959
re-enable-actions = "plone.meta.re_enable_actions:main"
6060
switch-to-pep420 = "plone.meta.pep_420:main"
61+
setup-to-pyproject = "plone.meta.setup_to_pyproject:main"
6162

6263
[tool.towncrier]
6364
directory = "news/"
@@ -119,4 +120,5 @@ omit = [
119120
"src/plone/meta/re_enable_actions.py",
120121
"src/plone/meta/pep_420.py",
121122
"src/plone/meta/multi_call.py",
123+
"src/plone/meta/setup_to_pyproject.py",
122124
]

src/plone/meta/config_package.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,45 @@ def _setuptools_upper_bound(self):
356356
return "82"
357357
return "83"
358358

359+
def _detect_setup_py_for_package_config(self):
360+
"""Dynamically find out if setup.py is used for package configuration.
361+
362+
If `pyproject.toml` contains some specific content, we assume that this
363+
file is used for package configuration, and `setup.py` is basically empty.
364+
Main reason: in that case `check-python-versions` fails if we ask it to
365+
check `setup.py`.
366+
"""
367+
if not (self.path / "setup.py").exists():
368+
# If the file does not even exist, it is definitely not used. ;-)
369+
return False
370+
pyproject = self.path / "pyproject.toml"
371+
if not pyproject.exists():
372+
# Should not happen. But if this file does not exist, then
373+
# `setup.py` will be used.
374+
return True
375+
text = pyproject.read_text()
376+
# If any of these markers do NOT exist in the `pyproject.toml` file,
377+
# we conclude that `setup.py` is still used.
378+
markers = [
379+
"START-MARKER-MANUAL-CONFIG",
380+
"[project]",
381+
"Programming Language :: Python",
382+
"requires-python",
383+
]
384+
return any([marker not in text for marker in markers])
385+
386+
def _check_python_versions_files(self, using_setup_py):
387+
"""Which files should be checked by check-python-versions?
388+
389+
This is for inclusion in the pre-commit config:
390+
391+
id: check-python-versions
392+
args: ['--only', 'setup.py,pyproject.toml']
393+
"""
394+
if using_setup_py:
395+
return "setup.py,tox.ini"
396+
return "pyproject.toml,tox.ini"
397+
359398
def pre_commit_config(self):
360399
options = self._get_options_for(
361400
"pre_commit",
@@ -370,6 +409,9 @@ def pre_commit_config(self):
370409

371410
python_version = self._minimal_python_version()
372411
options["minimal_python_version"] = self._no_dot_python_version(python_version)
412+
options["check_python_versions_files"] = self._check_python_versions_files(
413+
self._detect_setup_py_for_package_config()
414+
)
373415

374416
return self.copy_with_meta(
375417
"pre-commit-config.yaml.j2",

src/plone/meta/default/pre-commit-config.yaml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ repos:
6666
rev: "0.24.0"
6767
hooks:
6868
- id: check-python-versions
69-
args: ['--only', 'setup.py,pyproject.toml']
69+
args: ['--only', '%(check_python_versions_files)s']
7070
- repo: https://github.com/collective/i18ndude
7171
rev: "6.3.0"
7272
hooks:

0 commit comments

Comments
 (0)