ufo-spacing-lib 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,49 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ ENV/
27
+
28
+ # IDE
29
+ .idea/
30
+ .vscode/
31
+ *.swp
32
+ *.swo
33
+ .cursor/
34
+
35
+ # Testing
36
+ .pytest_cache/
37
+ .coverage
38
+ htmlcov/
39
+ .tox/
40
+ .nox/
41
+
42
+ # Type checking
43
+ .mypy_cache/
44
+
45
+ # Build
46
+ dist/
47
+ *.whl
48
+ PUBLISHING.md
49
+ .claude/
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Alexander Lubovenko
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.
22
+
@@ -0,0 +1,299 @@
1
+ Metadata-Version: 2.4
2
+ Name: ufo-spacing-lib
3
+ Version: 0.1.0
4
+ Summary: Font spacing management library for UFO-compatible fonts (kerning, margins, groups)
5
+ Project-URL: Homepage, https://github.com/typedev/ufo-spacing-lib
6
+ Project-URL: Repository, https://github.com/typedev/ufo-spacing-lib
7
+ Project-URL: Documentation, https://github.com/typedev/ufo-spacing-lib#readme
8
+ Project-URL: Issues, https://github.com/typedev/ufo-spacing-lib/issues
9
+ Author-email: Alexander Lubovenko <lubovenko@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: font,fonttools,kerning,spacing,type-design,typography,ufo
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
22
+ Classifier: Topic :: Text Processing :: Fonts
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.10
25
+ Provides-Extra: dev
26
+ Requires-Dist: mypy; extra == 'dev'
27
+ Requires-Dist: pytest-cov; extra == 'dev'
28
+ Requires-Dist: pytest>=7.0; extra == 'dev'
29
+ Requires-Dist: ruff; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # UFO Spacing Library
33
+
34
+ A framework-agnostic Python library for managing font spacing (kerning and margins) with full undo/redo support. Designed to work with UFO-compatible font objects.
35
+
36
+ ## Features
37
+
38
+ - **Framework Independent**: Works with any font editor that provides compatible font objects
39
+ - **Undo/Redo Support**: Full command pattern implementation with unlimited history
40
+ - **Multi-Font Operations**: Support for linked/interpolated fonts with per-font scaling
41
+ - **Preview/Simulation**: VirtualFont wrapper for testing changes without modifying real font
42
+ - **Composite Propagation**: Automatic margin propagation to composite glyphs
43
+ - **Well Documented**: Comprehensive docstrings and type hints throughout
44
+
45
+ ## Installation
46
+
47
+ ```bash
48
+ # From PyPI (when published)
49
+ pip install ufo-spacing-lib
50
+
51
+ # From source
52
+ pip install -e .
53
+
54
+ # Or with uv
55
+ uv pip install -e .
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ### Kerning Operations
61
+
62
+ ```python
63
+ from ufo_spacing_lib import (
64
+ KerningEditor,
65
+ FontContext,
66
+ AdjustKerningCommand,
67
+ SetKerningCommand,
68
+ RemoveKerningCommand,
69
+ )
70
+
71
+ # Create an editor
72
+ editor = KerningEditor()
73
+
74
+ # Create a context for your font
75
+ context = FontContext.from_single_font(font)
76
+
77
+ # Adjust kerning by a delta
78
+ cmd = AdjustKerningCommand(pair=('A', 'V'), delta=-10)
79
+ result = editor.execute(cmd, context)
80
+
81
+ # Set kerning to absolute value
82
+ cmd = SetKerningCommand(pair=('A', 'V'), value=-50)
83
+ editor.execute(cmd, context)
84
+
85
+ # Remove a kerning pair
86
+ cmd = RemoveKerningCommand(pair=('A', 'V'))
87
+ editor.execute(cmd, context)
88
+
89
+ # Undo/Redo
90
+ editor.undo()
91
+ editor.redo()
92
+ ```
93
+
94
+ ### Margins Operations
95
+
96
+ ```python
97
+ from ufo_spacing_lib import (
98
+ MarginsEditor,
99
+ FontContext,
100
+ AdjustMarginCommand,
101
+ SetMarginCommand,
102
+ )
103
+
104
+ editor = MarginsEditor()
105
+ context = FontContext.from_single_font(font)
106
+
107
+ # Adjust left margin (propagates to composites by default)
108
+ cmd = AdjustMarginCommand(
109
+ glyph_name='A',
110
+ side='left',
111
+ delta=10,
112
+ propagate_to_composites=True
113
+ )
114
+ editor.execute(cmd, context)
115
+
116
+ # Set right margin to absolute value
117
+ cmd = SetMarginCommand(
118
+ glyph_name='A',
119
+ side='right',
120
+ value=50
121
+ )
122
+ editor.execute(cmd, context)
123
+ ```
124
+
125
+ ### Multi-Font Operations (Interpolation)
126
+
127
+ ```python
128
+ # Create context for multiple fonts with scaling
129
+ context = FontContext.from_linked_fonts(
130
+ fonts=[light_master, regular_master, bold_master],
131
+ primary=regular_master,
132
+ scales={
133
+ light_master: 0.8,
134
+ regular_master: 1.0,
135
+ bold_master: 1.3
136
+ }
137
+ )
138
+
139
+ # Command applies to all fonts with appropriate scaling
140
+ cmd = AdjustKerningCommand(pair=('A', 'V'), delta=-10)
141
+ editor.execute(cmd, context)
142
+ # light_master: -8, regular_master: -10, bold_master: -13
143
+ ```
144
+
145
+ ### Event Callbacks
146
+
147
+ ```python
148
+ def on_kerning_change(command, result):
149
+ print(f"Kerning changed: {command.description}")
150
+ refresh_ui()
151
+
152
+ editor.on_change = on_kerning_change
153
+ editor.on_undo = on_kerning_change
154
+ editor.on_redo = on_kerning_change
155
+ ```
156
+
157
+ ### Preview/Simulation (VirtualFont)
158
+
159
+ ```python
160
+ from ufo_spacing_lib import VirtualFont, FontContext, AdjustKerningCommand
161
+
162
+ # Create virtual copy - isolates kerning/groups changes
163
+ virtual = VirtualFont.from_font(font)
164
+
165
+ # Work as usual - changes only affect virtual.kerning/groups
166
+ context = FontContext.from_single_font(virtual)
167
+ cmd = AdjustKerningCommand(pair=('A', 'V'), delta=-10)
168
+ editor.execute(cmd, context)
169
+
170
+ # Glyphs are live references - changes in font visible through virtual
171
+ print(virtual['A'].leftMargin) # Same as font['A'].leftMargin
172
+
173
+ # Check what changed
174
+ if virtual.has_changes():
175
+ for pair, (old, new) in virtual.get_kerning_diff().items():
176
+ print(f"{pair}: {old} -> {new}")
177
+
178
+ # Apply to real font when ready, or reset
179
+ virtual.apply_to(font) # Writes changes to font
180
+ # virtual.reset() # Discards all changes
181
+ ```
182
+
183
+ ## Architecture
184
+
185
+ ```
186
+ ufo_spacing_lib/
187
+ ├── __init__.py # Main exports
188
+ ├── contexts.py # FontContext class
189
+ ├── groups_core.py # FontGroupsManager, KernPairInfo, resolve_kern_pair
190
+ ├── virtual.py # VirtualFont for preview/simulation
191
+ ├── commands/
192
+ │ ├── __init__.py
193
+ │ ├── base.py # Command ABC, CommandResult
194
+ │ ├── kerning.py # Kerning commands
195
+ │ └── margins.py # Margins commands
196
+ └── editors/
197
+ ├── __init__.py
198
+ ├── kerning.py # KerningEditor
199
+ └── margins.py # MarginsEditor
200
+ ```
201
+
202
+ ## Font Object Interface
203
+
204
+ The library is designed to work with any font object that implements this interface:
205
+
206
+ ### For Kerning Operations
207
+
208
+ ```python
209
+ class FontKerning:
210
+ """Dict-like kerning access."""
211
+ def __getitem__(self, pair: Tuple[str, str]) -> int: ...
212
+ def __setitem__(self, pair: Tuple[str, str], value: int): ...
213
+ def __delitem__(self, pair: Tuple[str, str]): ...
214
+ def __contains__(self, pair: Tuple[str, str]) -> bool: ...
215
+ def get(self, pair: Tuple[str, str], default=None) -> Optional[int]: ...
216
+
217
+ class Font:
218
+ kerning: FontKerning
219
+ ```
220
+
221
+ ### For Margins Operations
222
+
223
+ ```python
224
+ class Glyph:
225
+ leftMargin: Optional[int]
226
+ rightMargin: Optional[int]
227
+ width: int
228
+ components: List[Component] # Optional
229
+
230
+ def moveBy(self, delta: Tuple[int, int]): ...
231
+ def changed(self): ... # Optional
232
+
233
+ class Component:
234
+ offset: Tuple[int, int]
235
+ def moveBy(self, delta: Tuple[int, int]): ...
236
+
237
+ class Font:
238
+ def __getitem__(self, glyph_name: str) -> Glyph: ...
239
+ def __contains__(self, glyph_name: str) -> bool: ...
240
+ def getReverseComponentMapping(self) -> Dict[str, List[str]]: ... # Optional
241
+ ```
242
+
243
+ ## Commands Reference
244
+
245
+ ### Kerning Commands
246
+
247
+ | Command | Description |
248
+ |---------|-------------|
249
+ | `SetKerningCommand(pair, value)` | Set kerning to absolute value |
250
+ | `AdjustKerningCommand(pair, delta)` | Adjust kerning by delta |
251
+ | `RemoveKerningCommand(pair)` | Remove a kerning pair |
252
+ | `CreateExceptionCommand(pair, value, side)` | Create kerning exception |
253
+
254
+ ### Margins Commands
255
+
256
+ | Command | Description |
257
+ |---------|-------------|
258
+ | `SetMarginCommand(glyph, side, value)` | Set margin to absolute value |
259
+ | `AdjustMarginCommand(glyph, side, delta)` | Adjust margin by delta |
260
+
261
+ All commands support:
262
+ - Multi-font operations via `FontContext`
263
+ - Per-font scaling
264
+ - Full undo/redo
265
+
266
+ ## Testing
267
+
268
+ The library includes 100+ unit tests covering all components.
269
+
270
+ ```bash
271
+ # Run all tests
272
+ PYTHONPATH=src python3 -m unittest discover -s tests -v
273
+
274
+ # Run specific test module
275
+ PYTHONPATH=src python3 -m unittest tests.test_kerning_commands -v
276
+
277
+ # With pytest (if installed)
278
+ PYTHONPATH=src python3 -m pytest tests/ -v
279
+ ```
280
+
281
+ ### Test Coverage
282
+
283
+ | Module | Tests | Coverage |
284
+ |--------|-------|----------|
285
+ | Kerning Commands | 25 | SetKerning, AdjustKerning, RemoveKerning, CreateException |
286
+ | Editors | 20 | KerningEditor, MarginsEditor, undo/redo, callbacks |
287
+ | Groups Manager | 30 | FontGroupsManager, add/remove/delete/rename groups |
288
+ | VirtualFont | 27 | Creation, isolation, glyph access, diff tracking, apply/reset |
289
+
290
+ ## License
291
+
292
+ MIT License
293
+
294
+ ## Author
295
+
296
+ Alexander Lubovenko
297
+ lubovenko@gmail.com
298
+ github.com/typedev
299
+
@@ -0,0 +1,268 @@
1
+ # UFO Spacing Library
2
+
3
+ A framework-agnostic Python library for managing font spacing (kerning and margins) with full undo/redo support. Designed to work with UFO-compatible font objects.
4
+
5
+ ## Features
6
+
7
+ - **Framework Independent**: Works with any font editor that provides compatible font objects
8
+ - **Undo/Redo Support**: Full command pattern implementation with unlimited history
9
+ - **Multi-Font Operations**: Support for linked/interpolated fonts with per-font scaling
10
+ - **Preview/Simulation**: VirtualFont wrapper for testing changes without modifying real font
11
+ - **Composite Propagation**: Automatic margin propagation to composite glyphs
12
+ - **Well Documented**: Comprehensive docstrings and type hints throughout
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ # From PyPI (when published)
18
+ pip install ufo-spacing-lib
19
+
20
+ # From source
21
+ pip install -e .
22
+
23
+ # Or with uv
24
+ uv pip install -e .
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Kerning Operations
30
+
31
+ ```python
32
+ from ufo_spacing_lib import (
33
+ KerningEditor,
34
+ FontContext,
35
+ AdjustKerningCommand,
36
+ SetKerningCommand,
37
+ RemoveKerningCommand,
38
+ )
39
+
40
+ # Create an editor
41
+ editor = KerningEditor()
42
+
43
+ # Create a context for your font
44
+ context = FontContext.from_single_font(font)
45
+
46
+ # Adjust kerning by a delta
47
+ cmd = AdjustKerningCommand(pair=('A', 'V'), delta=-10)
48
+ result = editor.execute(cmd, context)
49
+
50
+ # Set kerning to absolute value
51
+ cmd = SetKerningCommand(pair=('A', 'V'), value=-50)
52
+ editor.execute(cmd, context)
53
+
54
+ # Remove a kerning pair
55
+ cmd = RemoveKerningCommand(pair=('A', 'V'))
56
+ editor.execute(cmd, context)
57
+
58
+ # Undo/Redo
59
+ editor.undo()
60
+ editor.redo()
61
+ ```
62
+
63
+ ### Margins Operations
64
+
65
+ ```python
66
+ from ufo_spacing_lib import (
67
+ MarginsEditor,
68
+ FontContext,
69
+ AdjustMarginCommand,
70
+ SetMarginCommand,
71
+ )
72
+
73
+ editor = MarginsEditor()
74
+ context = FontContext.from_single_font(font)
75
+
76
+ # Adjust left margin (propagates to composites by default)
77
+ cmd = AdjustMarginCommand(
78
+ glyph_name='A',
79
+ side='left',
80
+ delta=10,
81
+ propagate_to_composites=True
82
+ )
83
+ editor.execute(cmd, context)
84
+
85
+ # Set right margin to absolute value
86
+ cmd = SetMarginCommand(
87
+ glyph_name='A',
88
+ side='right',
89
+ value=50
90
+ )
91
+ editor.execute(cmd, context)
92
+ ```
93
+
94
+ ### Multi-Font Operations (Interpolation)
95
+
96
+ ```python
97
+ # Create context for multiple fonts with scaling
98
+ context = FontContext.from_linked_fonts(
99
+ fonts=[light_master, regular_master, bold_master],
100
+ primary=regular_master,
101
+ scales={
102
+ light_master: 0.8,
103
+ regular_master: 1.0,
104
+ bold_master: 1.3
105
+ }
106
+ )
107
+
108
+ # Command applies to all fonts with appropriate scaling
109
+ cmd = AdjustKerningCommand(pair=('A', 'V'), delta=-10)
110
+ editor.execute(cmd, context)
111
+ # light_master: -8, regular_master: -10, bold_master: -13
112
+ ```
113
+
114
+ ### Event Callbacks
115
+
116
+ ```python
117
+ def on_kerning_change(command, result):
118
+ print(f"Kerning changed: {command.description}")
119
+ refresh_ui()
120
+
121
+ editor.on_change = on_kerning_change
122
+ editor.on_undo = on_kerning_change
123
+ editor.on_redo = on_kerning_change
124
+ ```
125
+
126
+ ### Preview/Simulation (VirtualFont)
127
+
128
+ ```python
129
+ from ufo_spacing_lib import VirtualFont, FontContext, AdjustKerningCommand
130
+
131
+ # Create virtual copy - isolates kerning/groups changes
132
+ virtual = VirtualFont.from_font(font)
133
+
134
+ # Work as usual - changes only affect virtual.kerning/groups
135
+ context = FontContext.from_single_font(virtual)
136
+ cmd = AdjustKerningCommand(pair=('A', 'V'), delta=-10)
137
+ editor.execute(cmd, context)
138
+
139
+ # Glyphs are live references - changes in font visible through virtual
140
+ print(virtual['A'].leftMargin) # Same as font['A'].leftMargin
141
+
142
+ # Check what changed
143
+ if virtual.has_changes():
144
+ for pair, (old, new) in virtual.get_kerning_diff().items():
145
+ print(f"{pair}: {old} -> {new}")
146
+
147
+ # Apply to real font when ready, or reset
148
+ virtual.apply_to(font) # Writes changes to font
149
+ # virtual.reset() # Discards all changes
150
+ ```
151
+
152
+ ## Architecture
153
+
154
+ ```
155
+ ufo_spacing_lib/
156
+ ├── __init__.py # Main exports
157
+ ├── contexts.py # FontContext class
158
+ ├── groups_core.py # FontGroupsManager, KernPairInfo, resolve_kern_pair
159
+ ├── virtual.py # VirtualFont for preview/simulation
160
+ ├── commands/
161
+ │ ├── __init__.py
162
+ │ ├── base.py # Command ABC, CommandResult
163
+ │ ├── kerning.py # Kerning commands
164
+ │ └── margins.py # Margins commands
165
+ └── editors/
166
+ ├── __init__.py
167
+ ├── kerning.py # KerningEditor
168
+ └── margins.py # MarginsEditor
169
+ ```
170
+
171
+ ## Font Object Interface
172
+
173
+ The library is designed to work with any font object that implements this interface:
174
+
175
+ ### For Kerning Operations
176
+
177
+ ```python
178
+ class FontKerning:
179
+ """Dict-like kerning access."""
180
+ def __getitem__(self, pair: Tuple[str, str]) -> int: ...
181
+ def __setitem__(self, pair: Tuple[str, str], value: int): ...
182
+ def __delitem__(self, pair: Tuple[str, str]): ...
183
+ def __contains__(self, pair: Tuple[str, str]) -> bool: ...
184
+ def get(self, pair: Tuple[str, str], default=None) -> Optional[int]: ...
185
+
186
+ class Font:
187
+ kerning: FontKerning
188
+ ```
189
+
190
+ ### For Margins Operations
191
+
192
+ ```python
193
+ class Glyph:
194
+ leftMargin: Optional[int]
195
+ rightMargin: Optional[int]
196
+ width: int
197
+ components: List[Component] # Optional
198
+
199
+ def moveBy(self, delta: Tuple[int, int]): ...
200
+ def changed(self): ... # Optional
201
+
202
+ class Component:
203
+ offset: Tuple[int, int]
204
+ def moveBy(self, delta: Tuple[int, int]): ...
205
+
206
+ class Font:
207
+ def __getitem__(self, glyph_name: str) -> Glyph: ...
208
+ def __contains__(self, glyph_name: str) -> bool: ...
209
+ def getReverseComponentMapping(self) -> Dict[str, List[str]]: ... # Optional
210
+ ```
211
+
212
+ ## Commands Reference
213
+
214
+ ### Kerning Commands
215
+
216
+ | Command | Description |
217
+ |---------|-------------|
218
+ | `SetKerningCommand(pair, value)` | Set kerning to absolute value |
219
+ | `AdjustKerningCommand(pair, delta)` | Adjust kerning by delta |
220
+ | `RemoveKerningCommand(pair)` | Remove a kerning pair |
221
+ | `CreateExceptionCommand(pair, value, side)` | Create kerning exception |
222
+
223
+ ### Margins Commands
224
+
225
+ | Command | Description |
226
+ |---------|-------------|
227
+ | `SetMarginCommand(glyph, side, value)` | Set margin to absolute value |
228
+ | `AdjustMarginCommand(glyph, side, delta)` | Adjust margin by delta |
229
+
230
+ All commands support:
231
+ - Multi-font operations via `FontContext`
232
+ - Per-font scaling
233
+ - Full undo/redo
234
+
235
+ ## Testing
236
+
237
+ The library includes 100+ unit tests covering all components.
238
+
239
+ ```bash
240
+ # Run all tests
241
+ PYTHONPATH=src python3 -m unittest discover -s tests -v
242
+
243
+ # Run specific test module
244
+ PYTHONPATH=src python3 -m unittest tests.test_kerning_commands -v
245
+
246
+ # With pytest (if installed)
247
+ PYTHONPATH=src python3 -m pytest tests/ -v
248
+ ```
249
+
250
+ ### Test Coverage
251
+
252
+ | Module | Tests | Coverage |
253
+ |--------|-------|----------|
254
+ | Kerning Commands | 25 | SetKerning, AdjustKerning, RemoveKerning, CreateException |
255
+ | Editors | 20 | KerningEditor, MarginsEditor, undo/redo, callbacks |
256
+ | Groups Manager | 30 | FontGroupsManager, add/remove/delete/rename groups |
257
+ | VirtualFont | 27 | Creation, isolation, glyph access, diff tracking, apply/reset |
258
+
259
+ ## License
260
+
261
+ MIT License
262
+
263
+ ## Author
264
+
265
+ Alexander Lubovenko
266
+ lubovenko@gmail.com
267
+ github.com/typedev
268
+
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ufo-spacing-lib"
7
+ version = "0.1.0"
8
+ description = "Font spacing management library for UFO-compatible fonts (kerning, margins, groups)"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Alexander Lubovenko", email = "lubovenko@gmail.com" }
14
+ ]
15
+ keywords = [
16
+ "font",
17
+ "typography",
18
+ "kerning",
19
+ "spacing",
20
+ "ufo",
21
+ "fonttools",
22
+ "type-design"
23
+ ]
24
+ classifiers = [
25
+ "Development Status :: 4 - Beta",
26
+ "Intended Audience :: Developers",
27
+ "License :: OSI Approved :: MIT License",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.10",
31
+ "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Topic :: Text Processing :: Fonts",
34
+ "Topic :: Multimedia :: Graphics :: Graphics Conversion",
35
+ "Typing :: Typed",
36
+ ]
37
+
38
+ [project.optional-dependencies]
39
+ dev = [
40
+ "pytest>=7.0",
41
+ "pytest-cov",
42
+ "ruff",
43
+ "mypy",
44
+ ]
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/typedev/ufo-spacing-lib"
48
+ Repository = "https://github.com/typedev/ufo-spacing-lib"
49
+ Documentation = "https://github.com/typedev/ufo-spacing-lib#readme"
50
+ Issues = "https://github.com/typedev/ufo-spacing-lib/issues"
51
+
52
+ [tool.hatch.build.targets.wheel]
53
+ packages = ["src/ufo_spacing_lib"]
54
+
55
+ [tool.hatch.build.targets.sdist]
56
+ include = [
57
+ "/src",
58
+ "/tests",
59
+ "/README.md",
60
+ "/LICENSE",
61
+ ]
62
+
63
+ [tool.ruff]
64
+ line-length = 88
65
+ target-version = "py310"
66
+
67
+ [tool.ruff.lint]
68
+ select = ["E", "F", "W", "I", "UP"]
69
+ ignore = ["E501"]
70
+
71
+ [tool.mypy]
72
+ python_version = "3.10"
73
+ warn_return_any = true
74
+ warn_unused_configs = true
75
+ ignore_missing_imports = true
76
+
77
+ [tool.pytest.ini_options]
78
+ testpaths = ["tests"]
79
+ python_files = "test_*.py"
80
+ python_functions = "test_*"
81
+