typekit2 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- typekit2-1.0.0/.env.example +3 -0
- typekit2-1.0.0/.gitignore +61 -0
- typekit2-1.0.0/CHANGELOG.md +29 -0
- typekit2-1.0.0/DEPENDENCIES.md +24 -0
- typekit2-1.0.0/LICENSE +21 -0
- typekit2-1.0.0/PKG-INFO +161 -0
- typekit2-1.0.0/PLAN.md +24 -0
- typekit2-1.0.0/README.md +137 -0
- typekit2-1.0.0/TODO.md +9 -0
- typekit2-1.0.0/WORK.md +22 -0
- typekit2-1.0.0/docs/API.md +45 -0
- typekit2-1.0.0/publish.sh +80 -0
- typekit2-1.0.0/pyproject.toml +90 -0
- typekit2-1.0.0/test.sh +9 -0
- typekit2-1.0.0/tests/test_cli.py +85 -0
- typekit2-1.0.0/tests/test_client.py +219 -0
- typekit2-1.0.0/tests/test_packaging.py +48 -0
- typekit2-1.0.0/typekit2/__init__.py +14 -0
- typekit2-1.0.0/typekit2/__main__.py +144 -0
- typekit2-1.0.0/typekit2/__version__.py +3 -0
- typekit2-1.0.0/typekit2/client.py +246 -0
- typekit2-1.0.0/typekit2/exceptions.py +29 -0
- typekit2-1.0.0/uv.lock +578 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# this_file: .gitignore
|
|
2
|
+
# Byte-compiled / optimized / DLL files
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
.DS_Store
|
|
6
|
+
.env
|
|
7
|
+
.venv/
|
|
8
|
+
.codegraph/
|
|
9
|
+
typekit2/__version__.py
|
|
10
|
+
|
|
11
|
+
# C extensions
|
|
12
|
+
*.so
|
|
13
|
+
|
|
14
|
+
# Distribution / packaging
|
|
15
|
+
.Python
|
|
16
|
+
env/
|
|
17
|
+
bin/
|
|
18
|
+
build/
|
|
19
|
+
develop-eggs/
|
|
20
|
+
dist/
|
|
21
|
+
eggs/
|
|
22
|
+
lib/
|
|
23
|
+
lib64/
|
|
24
|
+
parts/
|
|
25
|
+
sdist/
|
|
26
|
+
var/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
.installed.cfg
|
|
29
|
+
*.egg
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage reports
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.coverage
|
|
39
|
+
.cache
|
|
40
|
+
.pytest_cache/
|
|
41
|
+
.ruff_cache/
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
|
|
45
|
+
# Translations
|
|
46
|
+
*.mo
|
|
47
|
+
|
|
48
|
+
# Mr Developer
|
|
49
|
+
.mr.developer.cfg
|
|
50
|
+
.project
|
|
51
|
+
.pydevproject
|
|
52
|
+
|
|
53
|
+
# Rope
|
|
54
|
+
.ropeproject
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
*.pot
|
|
59
|
+
|
|
60
|
+
# Sphinx documentation
|
|
61
|
+
docs/_build/
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
this_file: CHANGELOG.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Changelog
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Renamed the distribution and import package from `typekit` to `typekit2`.
|
|
12
|
+
- Replaced `setup.py` with standards-based `pyproject.toml` packaging.
|
|
13
|
+
- Migrated the client from Python 2 to typed Python 3.10+.
|
|
14
|
+
- Switched authentication from URL query parameters to the documented HTTPS `X-Typekit-Token` header.
|
|
15
|
+
- Reworked kit writes to use current parameter shapes and preserve omitted update fields.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- `TYPEKIT_API_KEY` and `.env` configuration through `python-dotenv`.
|
|
20
|
+
- Fire CLI via `python -m typekit2` and the `typekit2` console command.
|
|
21
|
+
- Adobe Fonts API mapping and usage documentation.
|
|
22
|
+
- Offline tests for authentication, transport, payloads, errors, parsing, and CLI behavior.
|
|
23
|
+
- Tag-derived semantic versions using `hatch-vcs`.
|
|
24
|
+
- `publish.sh` workflow using `uvx gitnextver`, `uv build`, and `uv publish`.
|
|
25
|
+
|
|
26
|
+
### Removed
|
|
27
|
+
|
|
28
|
+
- Python 2-only code, live destructive tests, `setup.py`, and generated distutils manifest.
|
|
29
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
this_file: DEPENDENCIES.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Dependencies
|
|
6
|
+
|
|
7
|
+
## Runtime
|
|
8
|
+
|
|
9
|
+
- `requests`: HTTP transport with sessions, TLS verification, timeouts, and explicit status handling.
|
|
10
|
+
- `python-dotenv`: loads `TYPEKIT_API_KEY` from `.env` while preserving environment precedence.
|
|
11
|
+
- `fire`: generates the requested CLI from the small `TypekitCLI` command object.
|
|
12
|
+
|
|
13
|
+
## Build and release
|
|
14
|
+
|
|
15
|
+
- `hatchling`: PEP 517 build backend configured in `pyproject.toml`.
|
|
16
|
+
- `hatch-vcs`: derives PEP 440 versions from semantic Git tags and writes the packaged `__version__.py`.
|
|
17
|
+
- `gitnextver` (run with `uvx`): creates the next semantic version commit/tag and pushes it during releases.
|
|
18
|
+
- `uv`: resolves dependencies, runs checks, builds wheel/sdist, and publishes distributions.
|
|
19
|
+
|
|
20
|
+
## Development
|
|
21
|
+
|
|
22
|
+
- `pytest` and `pytest-cov`: offline contract tests and coverage enforcement.
|
|
23
|
+
- `ruff`: formatting and static lint checks.
|
|
24
|
+
|
typekit2-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Suchan Lee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
typekit2-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: typekit2
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Modern Python client and CLI for the Adobe Fonts (Typekit) API
|
|
5
|
+
Project-URL: Documentation, https://fonts.adobe.com/docs/api
|
|
6
|
+
Project-URL: Repository, https://github.com/fontlaborg/typekit-python
|
|
7
|
+
Author-email: Suchan Lee <lee.suchan@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: adobe-fonts,api,cli,typekit
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: fire>=0.7.1
|
|
21
|
+
Requires-Dist: python-dotenv>=1.2.3
|
|
22
|
+
Requires-Dist: requests>=2.32.5
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
this_file: README.md
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# typekit2
|
|
30
|
+
|
|
31
|
+
`typekit2` is a modern Python client and Fire CLI for the Adobe Fonts API formerly known as the Typekit API.
|
|
32
|
+
|
|
33
|
+
It replaces the abandoned `typekit` package’s Python 2 code and `setup.py` packaging with Python 3.10+, `pyproject.toml`, HTTPS header authentication, `.env` support, offline tests, and Git-tag-derived versions.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv add typekit2
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For local development:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv sync
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Create `.env` from the supplied example, or export the key directly:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cp .env.example .env
|
|
51
|
+
export TYPEKIT_API_KEY='your-token'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`python-dotenv` loads `.env` without overriding an existing environment variable. Never commit `.env`; it is ignored.
|
|
55
|
+
|
|
56
|
+
## Python API
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from typekit2 import Typekit
|
|
60
|
+
|
|
61
|
+
client = Typekit() # reads TYPEKIT_API_KEY
|
|
62
|
+
|
|
63
|
+
kits = client.list_kits()
|
|
64
|
+
family = client.get_font_family("pcpv")
|
|
65
|
+
variations = client.get_font_variations("pcpv")
|
|
66
|
+
library = client.get_library("full", page=1, per_page=50)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
An explicit key is also supported:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
client = Typekit(api_key="...")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The compatibility keyword `api_token=` is accepted, but new code should use `api_key=` or `TYPEKIT_API_KEY`.
|
|
76
|
+
|
|
77
|
+
### Kit workflow
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
created = client.create_kit(
|
|
81
|
+
"Example",
|
|
82
|
+
["example.com", "www.example.com"],
|
|
83
|
+
[{"id": "pcpv", "subset": "all", "variations": ["n4", "i4"]}],
|
|
84
|
+
)
|
|
85
|
+
kit_id = created["kit"]["id"]
|
|
86
|
+
|
|
87
|
+
client.update_kit(kit_id, name="Example renamed")
|
|
88
|
+
client.add_font(kit_id, "gkmg", variations=["n4", "n7"])
|
|
89
|
+
client.publish_kit(kit_id)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Publishing is asynchronous. Adobe documents that CDN propagation may take several minutes.
|
|
93
|
+
|
|
94
|
+
## CLI
|
|
95
|
+
|
|
96
|
+
The installed `typekit2` command and `python -m typekit2` expose the same Fire CLI. Results are stable JSON.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
typekit2 doctor
|
|
100
|
+
typekit2 kits
|
|
101
|
+
typekit2 kit abc123
|
|
102
|
+
typekit2 kit abc123 --published=true
|
|
103
|
+
typekit2 family pcpv
|
|
104
|
+
typekit2 variations pcpv
|
|
105
|
+
typekit2 libraries
|
|
106
|
+
typekit2 library full --page=1 --per-page=50
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Mutating commands are explicit:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
typekit2 create-kit Example --domains=example.com,www.example.com
|
|
113
|
+
typekit2 add-font abc123 pcpv --variations=n4,i4 --subset=all
|
|
114
|
+
typekit2 update-kit abc123 --name='Renamed kit'
|
|
115
|
+
typekit2 publish-kit abc123
|
|
116
|
+
typekit2 remove-font abc123 pcpv
|
|
117
|
+
typekit2 remove-kit abc123
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For `--families`, pass a JSON list:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
typekit2 create-kit Example \
|
|
124
|
+
--domains=example.com \
|
|
125
|
+
--families='[{"id":"pcpv","subset":"all","variations":["n4","i4"]}]'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Run `typekit2 --help` or `python -m typekit2 --help` for generated Fire help.
|
|
129
|
+
|
|
130
|
+
## API behavior
|
|
131
|
+
|
|
132
|
+
- Requests use `https://typekit.com/api/v1/json`.
|
|
133
|
+
- Authentication uses the documented `X-Typekit-Token` header; keys never enter URLs or CLI output.
|
|
134
|
+
- Kit writes use URL-encoded Rails-style nested parameters.
|
|
135
|
+
- A 30-second timeout is applied by default and can be changed with `Typekit(timeout=...)`.
|
|
136
|
+
- HTTP, JSON, and documented API errors raise `TypekitAPIError`.
|
|
137
|
+
- `update_kit` sends only supplied fields; omitted fields are not replaced accidentally.
|
|
138
|
+
|
|
139
|
+
See [docs/API.md](docs/API.md) for the method-to-endpoint map and links to Adobe’s authoritative documentation.
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
./test.sh
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The suite is offline: it uses request doubles and never creates, publishes, or deletes a real kit.
|
|
148
|
+
|
|
149
|
+
## Releases
|
|
150
|
+
|
|
151
|
+
Versions come from Git tags through `hatch-vcs`; generated `typekit2/__version__.py` is explicitly ignored. To validate, commit/tag/push the next semantic version, build fresh distributions, and publish with `uv`:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
./publish.sh
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Set `PUBLISH_SKIP_UPLOAD=1` to exercise the Git release and artifact verification flow without uploading to PyPI. `UV_PUBLISH_TOKEN` supplies a PyPI token when Trusted Publishing is unavailable.
|
|
158
|
+
|
|
159
|
+
## License and provenance
|
|
160
|
+
|
|
161
|
+
MIT. The project began as `typekit-python` by Suchan Lee; `typekit2` is its Python 3 modernization.
|
typekit2-1.0.0/PLAN.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
this_file: PLAN.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Plan
|
|
6
|
+
|
|
7
|
+
The modernization target is a maintained Python 3 package whose library, CLI, documentation, and release artifacts agree with the current Adobe Fonts API contract.
|
|
8
|
+
|
|
9
|
+
## Completed scope
|
|
10
|
+
|
|
11
|
+
- Rename both distribution and imports to `typekit2`.
|
|
12
|
+
- Replace legacy setup metadata with `pyproject.toml` and `hatch-vcs` versions.
|
|
13
|
+
- Modernize the HTTP client, HTTPS authentication, errors, typing, and API payloads.
|
|
14
|
+
- Load `TYPEKIT_API_KEY` from the environment or `.env`.
|
|
15
|
+
- Add a Fire CLI for reads and explicit kit mutations.
|
|
16
|
+
- Replace live account-mutating tests with deterministic request-level tests.
|
|
17
|
+
- Document Adobe endpoints, parameter semantics, installation, API, CLI, and releases.
|
|
18
|
+
- Add a guarded `gitnextver` and `uv publish` release workflow.
|
|
19
|
+
|
|
20
|
+
## Future work
|
|
21
|
+
|
|
22
|
+
- Add opt-in live read-only smoke tests when a dedicated Adobe Fonts test account is available.
|
|
23
|
+
- Add API resources only when they appear in Adobe’s authoritative reference.
|
|
24
|
+
|
typekit2-1.0.0/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
this_file: README.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# typekit2
|
|
6
|
+
|
|
7
|
+
`typekit2` is a modern Python client and Fire CLI for the Adobe Fonts API formerly known as the Typekit API.
|
|
8
|
+
|
|
9
|
+
It replaces the abandoned `typekit` package’s Python 2 code and `setup.py` packaging with Python 3.10+, `pyproject.toml`, HTTPS header authentication, `.env` support, offline tests, and Git-tag-derived versions.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv add typekit2
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For local development:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv sync
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Create `.env` from the supplied example, or export the key directly:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cp .env.example .env
|
|
27
|
+
export TYPEKIT_API_KEY='your-token'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`python-dotenv` loads `.env` without overriding an existing environment variable. Never commit `.env`; it is ignored.
|
|
31
|
+
|
|
32
|
+
## Python API
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from typekit2 import Typekit
|
|
36
|
+
|
|
37
|
+
client = Typekit() # reads TYPEKIT_API_KEY
|
|
38
|
+
|
|
39
|
+
kits = client.list_kits()
|
|
40
|
+
family = client.get_font_family("pcpv")
|
|
41
|
+
variations = client.get_font_variations("pcpv")
|
|
42
|
+
library = client.get_library("full", page=1, per_page=50)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
An explicit key is also supported:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
client = Typekit(api_key="...")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The compatibility keyword `api_token=` is accepted, but new code should use `api_key=` or `TYPEKIT_API_KEY`.
|
|
52
|
+
|
|
53
|
+
### Kit workflow
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
created = client.create_kit(
|
|
57
|
+
"Example",
|
|
58
|
+
["example.com", "www.example.com"],
|
|
59
|
+
[{"id": "pcpv", "subset": "all", "variations": ["n4", "i4"]}],
|
|
60
|
+
)
|
|
61
|
+
kit_id = created["kit"]["id"]
|
|
62
|
+
|
|
63
|
+
client.update_kit(kit_id, name="Example renamed")
|
|
64
|
+
client.add_font(kit_id, "gkmg", variations=["n4", "n7"])
|
|
65
|
+
client.publish_kit(kit_id)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Publishing is asynchronous. Adobe documents that CDN propagation may take several minutes.
|
|
69
|
+
|
|
70
|
+
## CLI
|
|
71
|
+
|
|
72
|
+
The installed `typekit2` command and `python -m typekit2` expose the same Fire CLI. Results are stable JSON.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
typekit2 doctor
|
|
76
|
+
typekit2 kits
|
|
77
|
+
typekit2 kit abc123
|
|
78
|
+
typekit2 kit abc123 --published=true
|
|
79
|
+
typekit2 family pcpv
|
|
80
|
+
typekit2 variations pcpv
|
|
81
|
+
typekit2 libraries
|
|
82
|
+
typekit2 library full --page=1 --per-page=50
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Mutating commands are explicit:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
typekit2 create-kit Example --domains=example.com,www.example.com
|
|
89
|
+
typekit2 add-font abc123 pcpv --variations=n4,i4 --subset=all
|
|
90
|
+
typekit2 update-kit abc123 --name='Renamed kit'
|
|
91
|
+
typekit2 publish-kit abc123
|
|
92
|
+
typekit2 remove-font abc123 pcpv
|
|
93
|
+
typekit2 remove-kit abc123
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
For `--families`, pass a JSON list:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
typekit2 create-kit Example \
|
|
100
|
+
--domains=example.com \
|
|
101
|
+
--families='[{"id":"pcpv","subset":"all","variations":["n4","i4"]}]'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Run `typekit2 --help` or `python -m typekit2 --help` for generated Fire help.
|
|
105
|
+
|
|
106
|
+
## API behavior
|
|
107
|
+
|
|
108
|
+
- Requests use `https://typekit.com/api/v1/json`.
|
|
109
|
+
- Authentication uses the documented `X-Typekit-Token` header; keys never enter URLs or CLI output.
|
|
110
|
+
- Kit writes use URL-encoded Rails-style nested parameters.
|
|
111
|
+
- A 30-second timeout is applied by default and can be changed with `Typekit(timeout=...)`.
|
|
112
|
+
- HTTP, JSON, and documented API errors raise `TypekitAPIError`.
|
|
113
|
+
- `update_kit` sends only supplied fields; omitted fields are not replaced accidentally.
|
|
114
|
+
|
|
115
|
+
See [docs/API.md](docs/API.md) for the method-to-endpoint map and links to Adobe’s authoritative documentation.
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
./test.sh
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The suite is offline: it uses request doubles and never creates, publishes, or deletes a real kit.
|
|
124
|
+
|
|
125
|
+
## Releases
|
|
126
|
+
|
|
127
|
+
Versions come from Git tags through `hatch-vcs`; generated `typekit2/__version__.py` is explicitly ignored. To validate, commit/tag/push the next semantic version, build fresh distributions, and publish with `uv`:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
./publish.sh
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Set `PUBLISH_SKIP_UPLOAD=1` to exercise the Git release and artifact verification flow without uploading to PyPI. `UV_PUBLISH_TOKEN` supplies a PyPI token when Trusted Publishing is unavailable.
|
|
134
|
+
|
|
135
|
+
## License and provenance
|
|
136
|
+
|
|
137
|
+
MIT. The project began as `typekit-python` by Suchan Lee; `typekit2` is its Python 3 modernization.
|
typekit2-1.0.0/TODO.md
ADDED
typekit2-1.0.0/WORK.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
this_file: WORK.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Work log
|
|
6
|
+
|
|
7
|
+
## 2026-09-20
|
|
8
|
+
|
|
9
|
+
- Audited the Python 2 package, destructive live tests, and setup metadata.
|
|
10
|
+
- Checked current Adobe Fonts authentication, request, parameter, kit, family, and library documentation.
|
|
11
|
+
- Checked current Python Fire, python-dotenv, hatch-vcs, and uv packaging guidance.
|
|
12
|
+
- Renamed the package to `typekit2` and implemented the modern client and CLI.
|
|
13
|
+
- Added offline contract tests before implementation.
|
|
14
|
+
- Added tag-derived versioning and a guarded publish workflow.
|
|
15
|
+
|
|
16
|
+
### Verification
|
|
17
|
+
|
|
18
|
+
- `ruff format --check` and `ruff check`: passed.
|
|
19
|
+
- Offline suite: 31 tests passed with 95.67% branch-aware coverage.
|
|
20
|
+
- Fresh `uv build --no-sources`: wheel and sdist built successfully; metadata names `typekit2`, the wheel contains `typekit2/__main__.py` and generated `typekit2/__version__.py`, and no legacy `typekit/` package is present.
|
|
21
|
+
- Installed-artifact smoke test from `/tmp`: both `typekit2 doctor` and `python -m typekit2 doctor` returned redacted JSON.
|
|
22
|
+
- Disposable release rehearsal: `publish.sh` advanced a local test repository from `v0.1.0` to `v0.1.1`, pushed matching branch/tag refs to a local bare remote, built matching artifacts, and skipped only PyPI upload under `PUBLISH_SKIP_UPLOAD=1`.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
this_file: docs/API.md
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Adobe Fonts API map
|
|
6
|
+
|
|
7
|
+
The service and URL paths retain the Typekit name even though the product is now Adobe Fonts. The authoritative documentation is the [Adobe Fonts Typekit API reference](https://fonts.adobe.com/docs/api).
|
|
8
|
+
|
|
9
|
+
## Authentication and transport
|
|
10
|
+
|
|
11
|
+
Adobe requires authenticated requests to use HTTPS. `typekit2` sends `TYPEKIT_API_KEY` as `X-Typekit-Token`, following the [authentication reference](https://fonts.adobe.com/docs/api/auth). It deliberately avoids the documented query-string fallback because URLs are commonly retained in logs and traces.
|
|
12
|
+
|
|
13
|
+
Form bodies follow Adobe’s [parameter encoding](https://fonts.adobe.com/docs/api/parameters): repeated values use `name[]`, while family objects use keys such as `families[0][id]`.
|
|
14
|
+
|
|
15
|
+
## Client methods
|
|
16
|
+
|
|
17
|
+
| Python method | HTTP endpoint | Notes |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `list_kits()` | `GET kits` | Authenticated user’s kits |
|
|
20
|
+
| `get_kit(id)` | `GET kits/:kit` | Current draft |
|
|
21
|
+
| `get_published_kit(id)` | `GET kits/:kit/published` | CDN-published version |
|
|
22
|
+
| `create_kit(...)` | `POST kits` | Creates a draft |
|
|
23
|
+
| `update_kit(...)` | `POST kits/:kit` | Supplied fields replace their current values |
|
|
24
|
+
| `remove_kit(id)` | `DELETE kits/:kit` | Permanent deletion |
|
|
25
|
+
| `publish_kit(id)` | `POST kits/:kit/publish` | Asynchronous publish |
|
|
26
|
+
| `add_font(...)` | `POST kits/:kit/families/:family` | Adds or replaces one family |
|
|
27
|
+
| `remove_font(...)` | `DELETE kits/:kit/families/:family` | Removes one family |
|
|
28
|
+
| `get_font_family(id)` | `GET families/:family` | IDs and slugs are accepted by Adobe |
|
|
29
|
+
| `get_font_variations(id)` | `GET families/:family` | Extracts FVD codes from the response |
|
|
30
|
+
| `list_libraries()` | `GET libraries` | Available font libraries |
|
|
31
|
+
| `get_library(...)` | `GET libraries/:library` | Supports `page` and `per_page` |
|
|
32
|
+
|
|
33
|
+
Reference pages: [kit manipulation](https://fonts.adobe.com/docs/api/kits), [font families](https://fonts.adobe.com/docs/api/v1/:format/families/:family), [libraries](https://fonts.adobe.com/docs/api/v1/:format/libraries), and [errors](https://fonts.adobe.com/docs/api/errors).
|
|
34
|
+
|
|
35
|
+
## Important semantics
|
|
36
|
+
|
|
37
|
+
- Draft changes are not live until `publish_kit` is called.
|
|
38
|
+
- Publishing returns before CDN propagation finishes.
|
|
39
|
+
- When an update parameter is supplied, Adobe replaces that parameter’s existing value.
|
|
40
|
+
- Font variations use Font Variation Description codes such as `n4` and `i7`.
|
|
41
|
+
- `subset` is either `default` or `all`.
|
|
42
|
+
- The legacy analytics option is deprecated by Adobe and is intentionally not exposed.
|
|
43
|
+
|
|
44
|
+
The upstream documentation is old in vocabulary but remains live and dated © 2026. `typekit2` documents only behavior supported by those current pages.
|
|
45
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# this_file: publish.sh
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
cd "$(dirname "${BASH_SOURCE[0]}")"
|
|
5
|
+
|
|
6
|
+
die() { printf '%s\n' "$*" >&2; exit 1; }
|
|
7
|
+
command -v uv >/dev/null || die 'uv is required.'
|
|
8
|
+
command -v uvx >/dev/null || die 'uvx is required.'
|
|
9
|
+
[[ "$(git rev-parse --show-prefix)" == "" ]] || die 'Run from the package Git root.'
|
|
10
|
+
git symbolic-ref --quiet HEAD >/dev/null || die 'Release from a branch, not detached HEAD.'
|
|
11
|
+
|
|
12
|
+
version_file=typekit2/__version__.py
|
|
13
|
+
git check-ignore --no-index -q "$version_file" || die "$version_file must be gitignored."
|
|
14
|
+
|
|
15
|
+
# Keep source changes for gitnextver to commit; remove only generated version dirt.
|
|
16
|
+
git rm --cached --ignore-unmatch -- "$version_file"
|
|
17
|
+
git clean -fX -- "$version_file" .DS_Store
|
|
18
|
+
uv sync --frozen --all-groups --reinstall-package typekit2
|
|
19
|
+
UV_FROZEN=1 ./test.sh
|
|
20
|
+
git clean -fX -- "$version_file" .DS_Store
|
|
21
|
+
|
|
22
|
+
# gitnextver stages source changes, creates the next SemVer commit/tag, and pushes.
|
|
23
|
+
uvx gitnextver --directory "$PWD"
|
|
24
|
+
[[ -z "$(git status --porcelain --untracked-files=all)" ]] || die 'gitnextver left uncommitted changes.'
|
|
25
|
+
release_tag=$(git describe --exact-match --tags --match 'v[0-9]*' HEAD) ||
|
|
26
|
+
die 'gitnextver did not create a release tag.'
|
|
27
|
+
[[ "$release_tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || die "Not a SemVer release tag: $release_tag"
|
|
28
|
+
|
|
29
|
+
# Revalidate because gitnextver may integrate upstream changes before tagging.
|
|
30
|
+
uv sync --frozen --all-groups --reinstall-package typekit2
|
|
31
|
+
UV_FROZEN=1 ./test.sh
|
|
32
|
+
[[ -z "$(git status --porcelain --untracked-files=all)" ]] || die 'Validation dirtied the release tree.'
|
|
33
|
+
|
|
34
|
+
# Prove branch and tag reached the remote instead of trusting a success banner.
|
|
35
|
+
remote=$(git remote | head -n 1)
|
|
36
|
+
if git remote get-url origin >/dev/null 2>&1; then remote=origin; fi
|
|
37
|
+
if [[ -n "$remote" ]]; then
|
|
38
|
+
branch=$(git symbolic-ref --short HEAD)
|
|
39
|
+
git push "$remote" "HEAD:refs/heads/$branch" "refs/tags/$release_tag"
|
|
40
|
+
remote_head=$(git ls-remote "$remote" "refs/heads/$branch" | cut -f1)
|
|
41
|
+
remote_tag=$(git ls-remote "$remote" "refs/tags/$release_tag" | cut -f1)
|
|
42
|
+
[[ "$remote_head" == "$(git rev-parse HEAD)" ]] || die 'Remote branch does not match HEAD.'
|
|
43
|
+
[[ "$remote_tag" == "$(git rev-parse "refs/tags/$release_tag")" ]] || die 'Remote tag mismatch.'
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# A fresh directory prevents stale dist artifacts from being uploaded.
|
|
47
|
+
release_dist=$(mktemp -d "${TMPDIR:-/tmp}/typekit2-release.XXXXXX")
|
|
48
|
+
trap 'rm -rf -- "$release_dist"' EXIT
|
|
49
|
+
uv build --no-sources --out-dir "$release_dist"
|
|
50
|
+
uv run --frozen python - "$release_tag" "$release_dist" <<'PY'
|
|
51
|
+
import email
|
|
52
|
+
from pathlib import Path
|
|
53
|
+
import sys
|
|
54
|
+
import tarfile
|
|
55
|
+
import zipfile
|
|
56
|
+
|
|
57
|
+
expected, folder = sys.argv[1].removeprefix("v"), Path(sys.argv[2])
|
|
58
|
+
wheels, sdists = list(folder.glob("*.whl")), list(folder.glob("*.tar.gz"))
|
|
59
|
+
assert len(wheels) == len(sdists) == 1, "Expected one wheel and one sdist"
|
|
60
|
+
with zipfile.ZipFile(wheels[0]) as wheel:
|
|
61
|
+
metadata_name = next(name for name in wheel.namelist() if name.endswith(".dist-info/METADATA"))
|
|
62
|
+
assert email.message_from_bytes(wheel.read(metadata_name))["Version"] == expected
|
|
63
|
+
generated = {}
|
|
64
|
+
exec(wheel.read("typekit2/__version__.py"), generated)
|
|
65
|
+
assert generated["__version__"] == expected
|
|
66
|
+
with tarfile.open(sdists[0]) as sdist:
|
|
67
|
+
metadata_name = next(member for member in sdist.getmembers() if member.name.endswith("/PKG-INFO"))
|
|
68
|
+
assert email.message_from_bytes(sdist.extractfile(metadata_name).read())["Version"] == expected
|
|
69
|
+
print(f"Verified wheel, sdist, and generated version: {expected}")
|
|
70
|
+
PY
|
|
71
|
+
[[ -z "$(git status --porcelain --untracked-files=all)" ]] || die 'Build dirtied the release tree.'
|
|
72
|
+
mkdir -p dist
|
|
73
|
+
cp "$release_dist"/*.whl "$release_dist"/*.tar.gz dist/
|
|
74
|
+
if [[ "${PUBLISH_SKIP_UPLOAD:-0}" == 1 ]]; then
|
|
75
|
+
printf 'Validated %s; PUBLISH_SKIP_UPLOAD=1 skips only the package upload.\n' "$release_tag"
|
|
76
|
+
else
|
|
77
|
+
uv publish "$release_dist"/*.whl "$release_dist"/*.tar.gz "$@"
|
|
78
|
+
printf 'Published %s.\n' "$release_tag"
|
|
79
|
+
fi
|
|
80
|
+
|