justmytype-pack-tools
Build tools for creating JustMyType font packs. Fetch font families from the google/fonts repo (or any GitHub repo), assemble pack directories, and generate pack_manifest.json. Usable from the justmytype_essentials mono-repo or standalone.
Commands
- fetch — Download configured font families from upstream (GitHub API) into a cache. Requires
source.refinupstream.toml. - build — Copy fetched families from cache into the pack’s
fonts/dir, resolve licenses (auto-detect + allowlist), and generatepack_manifest.json. Fails if a family’s license is unknown and not overridden. - manifest — Generate
pack_manifest.jsononly (fonts must already be present). Use after manual copy or when licenses are defined in config.
Usage (mono-repo)
From repo root:
just fetch western-core # fetch families into cache/
just build western-core # copy from cache + manifest
just dist western-core # build wheel
Or via CLI with shared cache:
pack-tools fetch packs/western-core --cache-dir cache
pack-tools build packs/western-core --cache-dir cache
Usage (standalone / other repos)
- Add an
upstream.tomlnext to your pack (see schema below). - Run from the pack directory or pass the pack path:
pack-tools fetch . --cache-dir ./cache
pack-tools build . --cache-dir ./cache
No dependency on packs/<name> layout; --cache-dir and pack path can be any directories.
upstream.toml schema
- [pack] —
name(required),version,entry_point,priority; optionaldescription,source_url,package_dir,display_name. - [source] —
repo(e.g.https://github.com/google/fonts),ref(commit SHA, branch, or tag; required for fetch/build), optionalarchive_sha256. - families — List of paths relative to repo root (e.g.
["ofl/inter", "apache/sourceserif4"]). Must match the upstream repo exactly (fetch fails with 404 if a path does not exist). - [[licenses]] — Optional static list of
spdxandpath(used bymanifestcommand when not using build). - [[license_overrides]] — Optional allowlist:
familypath +spdx. Use when auto-detection fails or to override; build fails if a family has no detected license and no override.
Example:
[pack]
name = "my-font-pack"
version = "0.1.0"
entry_point = "my-pack"
priority = 100
[source]
repo = "https://github.com/google/fonts"
ref = "main"
families = ["ofl/inter", "ofl/notosans"]
[[license_overrides]]
family = "ofl/inter"
spdx = "OFL-1.1"
Pack metadata semantics
Pack identity and display text are resolved in one place and used by both manifest and README generation.
| Field | Source | Meaning |
|---|---|---|
| name | [pack].name (required) |
Canonical code/package identifier; used for pip install and manifest pack.name. |
| display_name | [pack].display_name (optional) |
Short human-friendly title; written to manifest when set, used for README H1. If unset, pack-tools derives it for README from name. |
| description | [pack].description (optional) |
Longer descriptive text; written to manifest and README. |
| package_dir | [pack].package_dir (optional) |
When set, pack-tools uses src/{package_dir}/fonts for font layout. |
Manifest includes pack.name (always), and optionally pack.description and pack.display_name. README title and install command use the same resolved values so they stay consistent. When display_name is absent, the recommended fallback is pack.name; each application may choose what is most appropriate (e.g. humanizing pack.name).
License detection
Build uses strict auto-detection from each family directory (e.g. OFL.txt, LICENSE.txt, UFL.txt, Apache markers). If detection fails or is ambiguous, build fails unless that family is listed in [[license_overrides]].
Programmatic API
Other tools can run the same logic without shelling out to the CLI. Use the pipeline functions with typed request/result objects.
Full build (copy from cache + manifest + README, same as pack-tools build):
from pathlib import Path
from justmytype_pack_tools import run_build, BuildRequest
result = run_build(BuildRequest(pack_dir=Path("packs/western-core"), cache_dir=Path("cache")))
# result.font_root, result.manifest_path, result.readme_path, result.licenses
Fetch only:
from justmytype_pack_tools import run_fetch, FetchRequest
result = run_fetch(FetchRequest(pack_dir=Path("."), cache_dir=Path("./cache")))
# result.cache_root, result.families
Manifest only (fonts already in place):
from justmytype_pack_tools import run_manifest, ManifestRequest
result = run_manifest(ManifestRequest(pack_dir=Path("."), font_root=Path("src/pkg/fonts")))
# result.output_path, result.manifest
Build with stages toggled (e.g. copy + licenses but no README, or no manifest):
result = run_build(BuildRequest(
pack_dir=Path("."),
generate_manifest=True,
generate_readme=False,
))
Raises FileNotFoundError or ValueError on config/cache errors; handle as needed.
Manifest build timestamp
By default, generated pack_manifest.json does not include build.timestamp. That keeps manifests deterministic and makes diffs easier to trace (only source.ref, file hashes, and tool_version change when inputs change). To record build time for provenance, pass include_timestamp=True when calling the API (e.g. BuildRequest(..., include_timestamp=True) or ManifestRequest(..., include_timestamp=True)). The CLI does not add a flag for this; use the programmatic API if you need it.
Environment
- GITHUB_TOKEN or GH_TOKEN — Optional; increases rate limit for GitHub API.
Installation
From this directory: uv pip install -e . (or pip install -e .).
Metadata
Release files for justmytype-pack-tools 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| justmytype_pack_tools-0.2.1.tar.gz | 37.9 kB | Without provenance | Details for justmytype_pack_tools-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| justmytype_pack_tools-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for justmytype_pack_tools-0.2.1-py3-none-any.whl |
Total release size: 58.3 kB
Release files / justmytype_pack_tools-0.2.1.tar.gz
| Download URL | justmytype_pack_tools-0.2.1.tar.gz |
|---|---|
| Size | 37.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15fd936672a265927d55dec44042c0414838197799c069ceb6161268fa1e2196
|
|
BLAKE2b-256 checksum How to use checksums |
9559c48a77eff3c09c6ddbe847c424ce6e9b5eb597f95e5febacb154ef3c4112
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / justmytype_pack_tools-0.2.1-py3-none-any.whl
| Download URL | justmytype_pack_tools-0.2.1-py3-none-any.whl |
|---|---|
| Size | 20.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1cb7f25f0695220c79564d7072724cc443b6c477e29714b2cffd7635f29fb998
|
|
BLAKE2b-256 checksum How to use checksums |
b5ced38487328db86c38fec685bb27ae1497f6e6ccb105c86f0d868d3c7898e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for justmytype-pack-tools 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.