The PEP561 defines how to ensure that *.pyi files get included for
packaging. It does recommend to create a "py.typed" file in the module
directory. However that does NOT apply for "module-only packages", that
is a single python file without a directory (in src/).
Instead the pyi file has to be moved to a kind of typeshed whereas "mypy"
recognizes a stubs-module in the sys.path. So when we have "systemctl.py"
then the typhints are put into "systemctl-stubs/__init__.py".
In the real-world example of docker-systemctl-replacement the directory layout is
docker-systemctl-replacement/
src/
journalctl3.py
systemctl3.py
tests/
localtests2.py
Makefile
pyproject.toml
After running make 2 doing
strip-python3 --old-python --stubs src/systemctl3.py -o src/systemctl.py
then the directory structure is
docker-systemctl-replacement/
src/
journalctl3.py
systemctl3.py
systemctl.py
systemctl-stubs/
__init__.pyi
tests/
localtests2.py
Makefile
pyproject.toml
This will make pyproject.toml to pick up all *.py in src/ and the systemctl-stubs/ directory.
Location: /home/..../.local/lib/python3.11/site-packages
Files:
journalctl3.py
systemctl-stubs/__init__.pyi
systemctl.py
systemctl3.py
With that it is possible to write a short test file:
from systemctl import main
main()
and get it typechecked by "mypy" successfully as it can find the *.pyi for systemctl.py.
mypy --strict testprog.py
In the long run, projects should not use module-only packages anymore.
Instead you should rename the "src" folder into a versioned name (we use "strip3" in this project).
Then add the following to your pyproject.toml:
[tool.setuptools]
package-dir = {"strip3" = "strip3"}
And finally, add the py.typed which gets packaged from the versioned name directory.
echo PEP561 > strip3/py.typed
For bin-scripts you need to prepend the new versioned name, ofcourse.
[project.scripts]
strip-python3 = "strip3.strip_python3:main"