This page is meant to capture guidelines for Google Fonts Python projects.
It is written primarily based on the setup for picosvg, nanoemoji, gftools, and other projects.
We encourage the use of pyproject.toml
files rather than setup.py
to store project metadata, dependencies and tooling configuration. Become familiar with the Writing your pyproject.toml section of the Python packaging guide.
Here is an example pyproject.toml
, with reasoning for each section:
[build-system]
requires = [
# We continue to use `setuptools` rather than any "fancy" alternative
# package building/installation library
"setuptools>=45",
# We also want to use dynamic versioning, so that git tags become
# package versions.
"setuptools_scm[toml]>=6.2"
]
build-backend = "setuptools.build_meta"
# This section is optional; use it if you need to access the version number
# in your package for some reason.
[tool.setuptools_scm]
write_to = "src/mypackage/version.py"
[tool.setuptools.packages.find]
# Package files should be stored in the `src` directory.
# (Despite this recommendation, `Lib` is also commonly used.)
where = ["src"]
[project]
# This picks up the version number from git.
dynamic = ["version"]
name = "mypackage"
description = "Some clever fonts thing"
# Packages should have a README.md, which should be used for the pypi
# long description.
readme = "README.md"
authors = [
# { name = "You", email = "you@google.com" }
]
dependencies = [
# ... list runtime dependencies here ...
]
[project.optional-dependencies]
dev = [
# ... list dev dependencies here
]
# And any other optional extras
[project.scripts]
mypackage = "mypackage.__main__:main"
Key points:
Packages should use semantic versioning. This means: Breaking API changes require a major version bump. For packages which are still on version 0.x.y, breaking API changes should change the minor (x
) version number. (But you should also think carefully about what it would take for you to release 1.0.0…)
Releases should be automated through GitHub actions.
When declaring dependencies on packages we control, use both inclusive and exclusive ordered comparisons to ensure that (a) the latest version is always compatible but (b) you do not install a version with a different API profile. For example, if gftools
is currently at version 0.6.13
, declare a dependency on gftools >= 0.6.13, < 0.7
.
To automate the release with GitHub actions, use an action configuration
called .github/workflows/publish-release.yml
. (Copy the example action from gftools
and modify as appropriate.) In addition to the basic build/test, this action will:
In order to make this work, you will need to enable “Trusted publishing” for the repository in Pypi. This enables the release automation to publish the package.
Use git tag -a
to make a new annotated tag, or git tag -s
for a GPG-signed annotated tag, if you prefer.
Name the new tag with with a leading ‘v’ followed by three MAJOR.MINOR.PATCH digits, using semantic versioning. Look at the existing tags for examples.
In the tag message write some short release notes describing the changes since the previous tag.
Finally, push the tag to the remote repository (e.g. assuming upstream is called origin
):
$ git push origin v0.4.3
This will trigger the CI to build the distribution packages and upload them to the Python Package Index automatically, if all the tests pass successfully.
All projects should:
black
; ideally this should be tested on PR/commit.pylint
/ruff
checks.pytest
test suite, tested by the CI.TODO
Type hints are your friend. Use them liberally. Fail CI when pytype fails.
pyproject.toml
configures pytype. At least:
[tool.pytype]
inputs = ['mypackage']
You should also enable inline type hints:
[tool.setuptools.package-data]
mypackage = ["py.typed"]
Use Black
src/module_name/file.py
tests/file_tests.py
# also acceptable
tests/module_name/file_tests.py
.github/workflows/ci.yml # CI config (see comments in picosvg's example)
tox.ini # Config to tox test runner (TODO: why tox?)
pyproject.toml