Skip to content

Commit fb9a92e

Browse files
gforcadastevepiercymauritsvanrees
authored
Explain how to switch to add native namespace (#1981)
* feat: explain how to switch to add native namespace To go along with the PLIP 3928. * Update docs/developer-guide/native-namespaces.md Co-authored-by: Maurits van Rees <maurits@vanrees.org> * Add html_meta stuff * Condense sections and remove verbosity * Break sentence into two with relevant code blocks. Break another code block into separate code blocks for ease of copy-pasting into a shell session without comments. * - Rename file to singular - Break up single code block into multiple to make comments more legible and code copy-pasteable. - Clean up grammar and enhance MyST syntax --------- Co-authored-by: Steve Piercy <web@stevepiercy.com> Co-authored-by: Maurits van Rees <maurits@vanrees.org>
1 parent 81486c1 commit fb9a92e

File tree

2 files changed

+239
-0
lines changed

2 files changed

+239
-0
lines changed

docs/developer-guide/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ You can help consolidate all of development documentation here, even if it is to
2424
develop-volto-add-ons-index
2525
create-a-distribution
2626
standardize-python-project-configuration
27+
native-namespace
2728
```
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
---
2+
myst:
3+
html_meta:
4+
"description": "How to convert a Python distribution from a pkg_resources namespace to a native namespace"
5+
"property=og:description": "How to convert a Python distribution from a pkg_resources namespace to a native namespace"
6+
"property=og:title": "Native namespace"
7+
"keywords": "Plone 6, developer guide, native namespaces, pkg_resources, Python"
8+
---
9+
10+
# Native namespace
11+
12+
This chapter is guide for how to convert a Python distribution from a `pkg_resources` namespace to a native namespace.
13+
14+
Python 3.3 added support for native namespaces.
15+
See [PEP 420](https://peps.python.org/pep-0420/) for more details.
16+
17+
Plone has been using `pkg_resources`-style namespaces, but they are deprecated in `setuptools`.
18+
`setuptools` is planning to remove `pkg_resources`'s namespace support by the end of 2025.
19+
[PLIP 3928](https://github.com/plone/Products.CMFPlone/issues/3928) tracks the changes needed for Plone to adapt to the _new_ native namespaces.
20+
21+
To convert a given Python distribution to use a native namespace, follow these steps.
22+
23+
24+
## Create maintenance branch
25+
26+
```{note}
27+
This step is relevant only for Plone core packages.
28+
```
29+
30+
```{tip}
31+
This part is only needed when the `main` or `master` branch is used on multiple versions of the Plone core development buildout.
32+
```
33+
34+
If you haven't cloned the package's repository, then do so.
35+
36+
```shell
37+
git clone git@github.com:plone/$package
38+
cd $package
39+
```
40+
41+
Otherwise, pull the latest changes into your local repository.
42+
43+
```shell
44+
git fetch -p
45+
git checkout main # or master
46+
git rebase
47+
```
48+
49+
Find the last release tag, and create a branch for it.
50+
51+
List all tags.
52+
53+
```shell
54+
git for-each-ref --sort=taggerdate --format '%(tag)' refs/tags
55+
```
56+
57+
Get the last tag's major number.
58+
59+
```shell
60+
MAJOR=`git for-each-ref --sort=taggerdate --format '%(tag)' refs/tags | tail -n1 | cut -d"." -f1`
61+
```
62+
63+
Create a branch for it.
64+
65+
```shell
66+
git checkout -b $MAJOR.x
67+
```
68+
69+
Push the newly created branch.
70+
71+
```shell
72+
git push
73+
```
74+
75+
76+
## Update `buildout.coredev`
77+
78+
```{note}
79+
This step is relevant only for Plone core packages.
80+
```
81+
82+
Update `buildout.coredev`'s branch `6.1` to use the newly created branch.
83+
84+
```shell
85+
cd buildout.coredev
86+
```
87+
88+
Ensure you have the latest changes.
89+
90+
```shell
91+
git fetch -p
92+
git checkout 6.1
93+
git rebase
94+
```
95+
96+
Update the branch being used by the Python distribution.
97+
98+
```shell
99+
sed -i "s/$package.git branch=master/$package.git branch=$MAJOR.x/" sources.cfg
100+
```
101+
102+
Add the changes, commit, and push.
103+
104+
```shell
105+
git add sources.cfg
106+
git commit -m"chore: use branch $MAJOR.x for $package"
107+
git push
108+
```
109+
110+
Now check if you need to do the same on the `6.0` branch of `buildout.coredev`.
111+
112+
```{tip}
113+
You can use this [handy table](https://jenkins.plone.org/roboto/branches) to know which branch is used by a given package for each Plone version.
114+
```
115+
116+
```{tip}
117+
To lower the amount of builds in Jenkins, either do a few at a time or add a `[ci-skip]` on the commit message.
118+
```
119+
120+
## Counts before change
121+
122+
There is a risk when changing to the native namespaces that some files, or tests, might be left behind.
123+
To ensure all tests and files are kept after the switch, gather the counts before the change.
124+
125+
```shell
126+
tox run -e test -- --list-tests | wc -l
127+
```
128+
129+
```{note}
130+
Adapt to whichever way you are using to run the tests.
131+
The above is meant for repositories that follow `plone.meta` conventions.
132+
The `--list-tests` comes from `zope.testrunner`, if you are using that, but not `plone.meta`, although you can use that as well.
133+
```
134+
135+
Create a distribution to get a listing of how many files are currently packaged.
136+
137+
```shell
138+
rm -rf dist/
139+
uvx --from build pyproject-build
140+
```
141+
142+
A `dist` folder is created with two archives in it, one each with the file suffix of `.tar.gz` and `.whl`.
143+
To get the count of files in them, run the following commands.
144+
145+
```shell
146+
python -c "import glob; import tarfile; print(len(tarfile.open(glob.glob('dist/*.tar.gz')[0], 'r:gz').getnames()))"
147+
python -c "import glob; from zipfile import ZipFile; print(len(ZipFile(glob.glob('dist/*.whl')[0]).namelist()))"
148+
```
149+
150+
Note these counts for later in the step {ref}`compare-counts-after-change`.
151+
152+
153+
## Build backend
154+
155+
To ensure the package continues to build, verify that `setuptools` is defined as its build backend.
156+
For that, inspect the {file}`pyproject.toml`.
157+
It should have the following lines.
158+
159+
```toml
160+
[build-system]
161+
requires = ["setuptools>=68.2,<80", "wheel"]
162+
```
163+
164+
If they are not there, then add them, commit, and push the changes.
165+
166+
167+
## Convert to native namespace
168+
169+
Use `plone.meta`'s `switch-to-pep420` script.
170+
171+
```shell
172+
cd $package
173+
uvx --from plone.meta switch-to-pep420 --no-tests .
174+
```
175+
176+
```{tip}
177+
This will also bump the version to a new major release.
178+
179+
If the `main` or `master` branch is already an alpha version that is only used in Plone 6.2, you can specify that you don't want this version bump by adding the `--no-breaking` option.
180+
```
181+
182+
183+
## Update the test matrix
184+
185+
```{note}
186+
This step is relevant only for Plone core packages.
187+
```
188+
189+
Because the switch to the native namespace must be coordinated, all Python distributions need to be only for the same Plone version.
190+
In this case, it was decided to do it for the Plone 6.2 version.
191+
Thus, we need to ensure that the test matrix only tests against this Plone version.
192+
For that, update {file}`.meta.toml` with the following changes.
193+
194+
```toml
195+
[tox]
196+
test_matrix = {"6.2" = ["*"]}
197+
```
198+
199+
Update the scaffolding files with `plone.meta`.
200+
201+
```shell
202+
uvx --from plone.meta config-package --branch current .
203+
```
204+
205+
Review the changes and ensure all changes are sound.
206+
207+
```{note}
208+
If the diff is quite big, then run `config-package` before all the changes.
209+
Get the result into a pull request, approved, and merged.
210+
Then do a follow up pull request to move it to a native namespace.
211+
```
212+
213+
214+
(compare-counts-after-change)=
215+
216+
## Compare counts after change
217+
218+
Get the list of tests, and compare this result to the earlier one to ensure the same test counts.
219+
220+
```shell
221+
tox run -e test -- --list-tests | wc -l
222+
```
223+
224+
Similarly, create the distribution files and compare the numbers with the previous run.
225+
226+
```shell
227+
rm -rf dist/
228+
uvx --from build pyproject-build
229+
python -c "import glob; import tarfile; print(len(tarfile.open(glob.glob('dist/*.tar.gz')[0], 'r:gz').getnames()))"
230+
python -c "import glob; from zipfile import ZipFile; print(len(ZipFile(glob.glob('dist/*.whl')[0]).namelist()))"
231+
```
232+
233+
It is okay if the numbers are slightly lower.
234+
For obvious reasons, the old source distribution will have one or more extra {file}`__init__.py` files.
235+
Both old distributions are expected to have an extra {file}`namespace_packages.txt` file and possibly an {file}`x-nspkg.pth` file.
236+
If you lose more than a few files though, something is wrong.
237+
238+
If the numbers are close enough, review the changes once more, and push the branch with the changes for others to review it.

0 commit comments

Comments
 (0)