justmytype 0.1.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.
@@ -0,0 +1,7 @@
1
+ Copyright 2026 Kaj Wik Siebert
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.3
2
+ Name: justmytype
3
+ Version: 0.1.0
4
+ Summary: Cross-platform font discovery and resolution library for Python
5
+ License: MIT
6
+ Author: Kaj Siebert
7
+ Author-email: kaj@k-si.com
8
+ Requires-Python: >=3.10
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Provides-Extra: dev
16
+ Provides-Extra: pillow
17
+ Requires-Dist: Pillow (>=9.0.0) ; extra == "pillow"
18
+ Requires-Dist: coverage (>=7.0.0) ; extra == "dev"
19
+ Requires-Dist: mypy (>=1.0.0) ; extra == "dev"
20
+ Requires-Dist: pytest (>=7.0.0) ; extra == "dev"
21
+ Requires-Dist: pytest-cov (>=4.0.0) ; extra == "dev"
22
+ Requires-Dist: ruff (>=0.1.0) ; extra == "dev"
23
+ Project-URL: Homepage, https://github.com/kws/justmytype
24
+ Project-URL: Issues, https://github.com/kws/justmytype/issues
25
+ Project-URL: Repository, https://github.com/kws/justmytype
26
+ Description-Content-Type: text/markdown
27
+
28
+ # JustMyType
29
+
30
+ A precise, lightweight, and extensible font discovery library for Python. JustMyType provides a robust "Font Atlas" for the Python ecosystem—a definitive map of every font available to an application, whether installed on the system or bundled in a Python package.
31
+
32
+ ## Features
33
+
34
+ - **Cross-platform**: Unified API across macOS, Linux, and Windows
35
+ - **Extensible**: Font packs can be added via standard Python EntryPoints mechanism
36
+ - **Efficient**: Lazy discovery with in-memory caching
37
+ - **Flexible**: Supports font matching by family, weight, style, and width with intelligent fallback
38
+ - **W3C Compliant**: Implements CSS Fonts Level 4 matching algorithm for browser-like behavior
39
+ - **Precise**: Uses `fonttools` to parse binary font tables—never guesses from filenames
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install justmytype
45
+ ```
46
+
47
+ For Pillow support (optional, for loading fonts):
48
+
49
+ ```bash
50
+ pip install justmytype[pillow]
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ ```python
56
+ from justmytype import FontRegistry, get_default_registry
57
+
58
+ # Get default registry
59
+ registry = get_default_registry()
60
+
61
+ # Find a font (lazy discovery happens automatically)
62
+ font_info = registry.find_font("Arial", weight=700, style="normal")
63
+ if font_info:
64
+ # Load as PIL ImageFont (requires Pillow)
65
+ font = font_info.load(size=16)
66
+
67
+ # Or use the path directly
68
+ print(f"Found font at: {font_info.path}")
69
+ ```
70
+
71
+ ## Basic Usage
72
+
73
+ ### Finding Fonts
74
+
75
+ ```python
76
+ from justmytype import FontRegistry
77
+
78
+ registry = FontRegistry()
79
+
80
+ # Find by family name
81
+ font_info = registry.find_font("Roboto", weight=400)
82
+
83
+ # Find with style
84
+ font_info = registry.find_font("Open Sans", weight=700, style="italic")
85
+
86
+ # Find with width
87
+ font_info = registry.find_font("Arial", width="condensed")
88
+
89
+ # List all available families
90
+ for family in registry.list_families():
91
+ print(family)
92
+ ```
93
+
94
+ ### Loading Fonts with Pillow
95
+
96
+ ```python
97
+ from justmytype import get_default_registry
98
+ from PIL import Image, ImageDraw, ImageFont
99
+
100
+ registry = get_default_registry()
101
+ font_info = registry.find_font("Arial", weight=700)
102
+
103
+ if font_info:
104
+ # Load as PIL ImageFont
105
+ font = font_info.load(size=24)
106
+
107
+ # Use with PIL
108
+ img = Image.new("RGB", (200, 100), "white")
109
+ draw = ImageDraw.Draw(img)
110
+ draw.text((10, 10), "Hello", font=font, fill="black")
111
+ img.save("output.png")
112
+ ```
113
+
114
+ ### Blocking Font Packs
115
+
116
+ ```python
117
+ # Block system fonts
118
+ registry = FontRegistry(blocklist={"system-fonts"})
119
+
120
+ # Block via environment variable
121
+ # FONT_DISCOVERY_BLOCKLIST="system-fonts,broken-pack" python app.py
122
+ ```
123
+
124
+ ## Creating Font Packs
125
+
126
+ Font packs can be registered via Python EntryPoints. This allows applications to bundle fonts or third-party packages to provide fonts.
127
+
128
+ ### First-Party Font Pack (Application's Own Fonts)
129
+
130
+ ```python
131
+ # myapp/fonts.py
132
+ from pathlib import Path
133
+ from importlib.resources import files
134
+
135
+ def get_font_directories():
136
+ """Entry point factory for application's bundled fonts."""
137
+ package = files("myapp.fonts")
138
+ return [Path(str(package))]
139
+ ```
140
+
141
+ ```toml
142
+ # pyproject.toml
143
+ [project.entry-points."fontpacks"]
144
+ "myapp-fonts" = "myapp.fonts:get_font_directories"
145
+ ```
146
+
147
+ ### Third-Party Font Pack
148
+
149
+ ```python
150
+ # my_font_pack/__init__.py
151
+ from pathlib import Path
152
+ from importlib.resources import files
153
+
154
+ def get_font_directories():
155
+ """Entry point factory for font pack."""
156
+ package = files("my_font_pack.fonts")
157
+ return [Path(str(package))]
158
+ ```
159
+
160
+ ## Architecture
161
+
162
+ JustMyType follows a unified "Font Pack" architecture where all font sources (system fonts, bundled fonts, third-party fonts) implement the same `FontPack` protocol. This ensures:
163
+
164
+ - **Consistency**: All fonts are discovered and resolved the same way
165
+ - **Extensibility**: New font sources can be added via EntryPoints
166
+ - **Priority**: Font packs (priority 100) override system fonts (priority 0)
167
+
168
+ See `docs/architecture.md` for detailed architecture documentation.
169
+
170
+ ## Development
171
+
172
+ ### Setup
173
+
174
+ ```bash
175
+ # Clone the repository
176
+ git clone https://github.com/yourusername/justmytype.git
177
+ cd justmytype
178
+
179
+ # Install with development dependencies
180
+ pip install -e ".[pillow]"
181
+ pip install -e ".[dev]" # If dev dependencies are configured
182
+ ```
183
+
184
+ ### Running Tests
185
+
186
+ ```bash
187
+ # Run tests with coverage
188
+ pytest
189
+
190
+ # Run with coverage report
191
+ pytest --cov=justmytype --cov-report=html
192
+ ```
193
+
194
+ ### Code Quality
195
+
196
+ ```bash
197
+ # Format code
198
+ ruff format .
199
+
200
+ # Lint code
201
+ ruff check .
202
+
203
+ # Type checking
204
+ mypy src/
205
+ ```
206
+
207
+ ## Requirements
208
+
209
+ - Python 3.10+
210
+ - `fonttools` (required)
211
+ - `Pillow` (optional, for `FontInfo.load()`)
212
+
213
+ ## License
214
+
215
+ MIT License - see LICENSE file for details.
216
+
217
+ ## Contributing
218
+
219
+ Contributions are welcome! Please read the architecture documentation in `docs/architecture.md` and follow the project philosophy outlined in `AGENTS.md`.
220
+
@@ -0,0 +1,192 @@
1
+ # JustMyType
2
+
3
+ A precise, lightweight, and extensible font discovery library for Python. JustMyType provides a robust "Font Atlas" for the Python ecosystem—a definitive map of every font available to an application, whether installed on the system or bundled in a Python package.
4
+
5
+ ## Features
6
+
7
+ - **Cross-platform**: Unified API across macOS, Linux, and Windows
8
+ - **Extensible**: Font packs can be added via standard Python EntryPoints mechanism
9
+ - **Efficient**: Lazy discovery with in-memory caching
10
+ - **Flexible**: Supports font matching by family, weight, style, and width with intelligent fallback
11
+ - **W3C Compliant**: Implements CSS Fonts Level 4 matching algorithm for browser-like behavior
12
+ - **Precise**: Uses `fonttools` to parse binary font tables—never guesses from filenames
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install justmytype
18
+ ```
19
+
20
+ For Pillow support (optional, for loading fonts):
21
+
22
+ ```bash
23
+ pip install justmytype[pillow]
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```python
29
+ from justmytype import FontRegistry, get_default_registry
30
+
31
+ # Get default registry
32
+ registry = get_default_registry()
33
+
34
+ # Find a font (lazy discovery happens automatically)
35
+ font_info = registry.find_font("Arial", weight=700, style="normal")
36
+ if font_info:
37
+ # Load as PIL ImageFont (requires Pillow)
38
+ font = font_info.load(size=16)
39
+
40
+ # Or use the path directly
41
+ print(f"Found font at: {font_info.path}")
42
+ ```
43
+
44
+ ## Basic Usage
45
+
46
+ ### Finding Fonts
47
+
48
+ ```python
49
+ from justmytype import FontRegistry
50
+
51
+ registry = FontRegistry()
52
+
53
+ # Find by family name
54
+ font_info = registry.find_font("Roboto", weight=400)
55
+
56
+ # Find with style
57
+ font_info = registry.find_font("Open Sans", weight=700, style="italic")
58
+
59
+ # Find with width
60
+ font_info = registry.find_font("Arial", width="condensed")
61
+
62
+ # List all available families
63
+ for family in registry.list_families():
64
+ print(family)
65
+ ```
66
+
67
+ ### Loading Fonts with Pillow
68
+
69
+ ```python
70
+ from justmytype import get_default_registry
71
+ from PIL import Image, ImageDraw, ImageFont
72
+
73
+ registry = get_default_registry()
74
+ font_info = registry.find_font("Arial", weight=700)
75
+
76
+ if font_info:
77
+ # Load as PIL ImageFont
78
+ font = font_info.load(size=24)
79
+
80
+ # Use with PIL
81
+ img = Image.new("RGB", (200, 100), "white")
82
+ draw = ImageDraw.Draw(img)
83
+ draw.text((10, 10), "Hello", font=font, fill="black")
84
+ img.save("output.png")
85
+ ```
86
+
87
+ ### Blocking Font Packs
88
+
89
+ ```python
90
+ # Block system fonts
91
+ registry = FontRegistry(blocklist={"system-fonts"})
92
+
93
+ # Block via environment variable
94
+ # FONT_DISCOVERY_BLOCKLIST="system-fonts,broken-pack" python app.py
95
+ ```
96
+
97
+ ## Creating Font Packs
98
+
99
+ Font packs can be registered via Python EntryPoints. This allows applications to bundle fonts or third-party packages to provide fonts.
100
+
101
+ ### First-Party Font Pack (Application's Own Fonts)
102
+
103
+ ```python
104
+ # myapp/fonts.py
105
+ from pathlib import Path
106
+ from importlib.resources import files
107
+
108
+ def get_font_directories():
109
+ """Entry point factory for application's bundled fonts."""
110
+ package = files("myapp.fonts")
111
+ return [Path(str(package))]
112
+ ```
113
+
114
+ ```toml
115
+ # pyproject.toml
116
+ [project.entry-points."fontpacks"]
117
+ "myapp-fonts" = "myapp.fonts:get_font_directories"
118
+ ```
119
+
120
+ ### Third-Party Font Pack
121
+
122
+ ```python
123
+ # my_font_pack/__init__.py
124
+ from pathlib import Path
125
+ from importlib.resources import files
126
+
127
+ def get_font_directories():
128
+ """Entry point factory for font pack."""
129
+ package = files("my_font_pack.fonts")
130
+ return [Path(str(package))]
131
+ ```
132
+
133
+ ## Architecture
134
+
135
+ JustMyType follows a unified "Font Pack" architecture where all font sources (system fonts, bundled fonts, third-party fonts) implement the same `FontPack` protocol. This ensures:
136
+
137
+ - **Consistency**: All fonts are discovered and resolved the same way
138
+ - **Extensibility**: New font sources can be added via EntryPoints
139
+ - **Priority**: Font packs (priority 100) override system fonts (priority 0)
140
+
141
+ See `docs/architecture.md` for detailed architecture documentation.
142
+
143
+ ## Development
144
+
145
+ ### Setup
146
+
147
+ ```bash
148
+ # Clone the repository
149
+ git clone https://github.com/yourusername/justmytype.git
150
+ cd justmytype
151
+
152
+ # Install with development dependencies
153
+ pip install -e ".[pillow]"
154
+ pip install -e ".[dev]" # If dev dependencies are configured
155
+ ```
156
+
157
+ ### Running Tests
158
+
159
+ ```bash
160
+ # Run tests with coverage
161
+ pytest
162
+
163
+ # Run with coverage report
164
+ pytest --cov=justmytype --cov-report=html
165
+ ```
166
+
167
+ ### Code Quality
168
+
169
+ ```bash
170
+ # Format code
171
+ ruff format .
172
+
173
+ # Lint code
174
+ ruff check .
175
+
176
+ # Type checking
177
+ mypy src/
178
+ ```
179
+
180
+ ## Requirements
181
+
182
+ - Python 3.10+
183
+ - `fonttools` (required)
184
+ - `Pillow` (optional, for `FontInfo.load()`)
185
+
186
+ ## License
187
+
188
+ MIT License - see LICENSE file for details.
189
+
190
+ ## Contributing
191
+
192
+ Contributions are welcome! Please read the architecture documentation in `docs/architecture.md` and follow the project philosophy outlined in `AGENTS.md`.
@@ -0,0 +1,141 @@
1
+ [project]
2
+ name = "justmytype"
3
+ version = "0.1.0"
4
+ description = "Cross-platform font discovery and resolution library for Python"
5
+ authors = [
6
+ {name = "Kaj Siebert", email = "kaj@k-si.com"}
7
+ ]
8
+ license = {text = "MIT"}
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+
12
+ [project.optional-dependencies]
13
+ pillow = ["Pillow>=9.0.0"]
14
+ dev = [
15
+ "pytest>=7.0.0",
16
+ "pytest-cov>=4.0.0",
17
+ "coverage>=7.0.0",
18
+ "ruff>=0.1.0",
19
+ "mypy>=1.0.0",
20
+ ]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/kws/justmytype"
24
+ Repository = "https://github.com/kws/justmytype"
25
+ Issues = "https://github.com/kws/justmytype/issues"
26
+
27
+ [project.entry-points."fontpacks"]
28
+ # Entry point group for font pack discovery
29
+ # Example: "my-font-pack" = "my_font_pack:get_font_directories"
30
+
31
+ [build-system]
32
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
33
+ build-backend = "poetry.core.masonry.api"
34
+
35
+ [tool.poetry]
36
+ # Poetry configuration for PEP 621 compatibility
37
+ # All project metadata is defined in [project] above
38
+
39
+ [tool.poetry.dependencies]
40
+ python = ">=3.10"
41
+ fonttools = ">=4.0.0"
42
+
43
+ [tool.poetry.group.dev.dependencies]
44
+ pytest = ">=7.0.0"
45
+ pytest-cov = ">=4.0.0"
46
+ coverage = ">=7.0.0"
47
+ ruff = ">=0.1.0"
48
+ mypy = ">=1.0.0"
49
+ pre-commit = ">=3.0.0"
50
+
51
+ [tool.ruff]
52
+ line-length = 88
53
+ target-version = "py310"
54
+
55
+ [tool.ruff.lint]
56
+ select = [
57
+ "E", # pycodestyle errors
58
+ "W", # pycodestyle warnings
59
+ "F", # pyflakes
60
+ "I", # isort
61
+ "N", # pep8-naming
62
+ "UP", # pyupgrade
63
+ "B", # flake8-bugbear
64
+ "C4", # flake8-comprehensions
65
+ ]
66
+ ignore = [
67
+ "E501", # line too long (handled by formatter)
68
+ ]
69
+
70
+ [tool.ruff.lint.isort]
71
+ known-first-party = ["justmytype"]
72
+
73
+ [tool.ruff.format]
74
+ quote-style = "double"
75
+ indent-style = "space"
76
+ skip-magic-trailing-comma = false
77
+ line-ending = "auto"
78
+
79
+ [tool.pytest.ini_options]
80
+ testpaths = ["tests"]
81
+ python_files = ["test_*.py"]
82
+ python_classes = ["Test*"]
83
+ python_functions = ["test_*"]
84
+ addopts = [
85
+ "--strict-markers",
86
+ "--strict-config",
87
+ "--cov=justmytype",
88
+ "--cov-report=term-missing",
89
+ "--cov-report=html",
90
+ "--cov-report=xml",
91
+ "--cov-fail-under=90",
92
+ ]
93
+ markers = [
94
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
95
+ "integration: marks tests as integration tests",
96
+ ]
97
+
98
+ [tool.coverage.run]
99
+ source = ["src"]
100
+ omit = [
101
+ "*/tests/*",
102
+ "*/test_*",
103
+ "*/__pycache__/*",
104
+ ]
105
+
106
+ [tool.coverage.report]
107
+ exclude_lines = [
108
+ "pragma: no cover",
109
+ "def __repr__",
110
+ "raise AssertionError",
111
+ "raise NotImplementedError",
112
+ "if __name__ == .__main__.:",
113
+ "if TYPE_CHECKING:",
114
+ "@abstractmethod",
115
+ "class .*\\bProtocol\\):",
116
+ "if False:",
117
+ ]
118
+
119
+ [tool.mypy]
120
+ python_version = "3.10"
121
+ strict = true
122
+ warn_return_any = true
123
+ warn_unused_configs = true
124
+ disallow_untyped_defs = true
125
+ disallow_incomplete_defs = true
126
+ check_untyped_defs = true
127
+ disallow_untyped_decorators = true
128
+ no_implicit_optional = true
129
+ warn_redundant_casts = true
130
+ warn_unused_ignores = true
131
+ warn_no_return = true
132
+ warn_unreachable = true
133
+ strict_equality = true
134
+ show_error_codes = true
135
+
136
+ [[tool.mypy.overrides]]
137
+ module = [
138
+ "fonttools.*",
139
+ "PIL.*",
140
+ ]
141
+ ignore_missing_imports = true
@@ -0,0 +1,15 @@
1
+ """JustMyType - Cross-platform font discovery and resolution library."""
2
+
3
+ from justmytype.core import FontRegistry, get_default_registry
4
+ from justmytype.packs.factory import create_system_font_pack
5
+ from justmytype.types import FontInfo, FontPack
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ __all__ = [
10
+ "FontInfo",
11
+ "FontPack",
12
+ "FontRegistry",
13
+ "create_system_font_pack",
14
+ "get_default_registry",
15
+ ]