0
# Plugin System
1
2
Extensible plugin architecture supporting custom builders, build hooks, version sources, version schemes, and metadata hooks. The plugin system enables third-party extensions and customization of hatchling's functionality.
3
4
## Capabilities
5
6
### Plugin Manager
7
8
Central plugin management system that discovers, loads, and manages all plugin types.
9
10
```python { .api }
11
class PluginManager:
12
def __init__(self):
13
"""
14
Initialize plugin manager.
15
16
Note:
17
The PluginManager uses dynamic initialization and does not
18
require parameters during construction.
19
"""
20
21
@property
22
def builders(self) -> dict[str, type[BuilderInterface]]:
23
"""Dictionary of available builder plugins."""
24
25
@property
26
def build_hooks(self) -> dict[str, type[BuildHookInterface]]:
27
"""Dictionary of available build hook plugins."""
28
29
@property
30
def version_sources(self) -> dict[str, type[VersionSourceInterface]]:
31
"""Dictionary of available version source plugins."""
32
33
@property
34
def version_schemes(self) -> dict[str, type[VersionSchemeInterface]]:
35
"""Dictionary of available version scheme plugins."""
36
37
@property
38
def metadata_hooks(self) -> dict[str, type[MetadataHookInterface]]:
39
"""Dictionary of available metadata hook plugins."""
40
```
41
42
### Builder Interface
43
44
Abstract base class for all builder plugins.
45
46
```python { .api }
47
class BuilderInterface(ABC, Generic[BuilderConfigBound, PluginManagerBound]):
48
def build(
49
self, *,
50
directory: str | None = None,
51
versions: list[str] | None = None,
52
hooks_only: bool | None = None,
53
clean: bool | None = None,
54
clean_hooks_after: bool | None = None,
55
clean_only: bool | None = False
56
) -> Generator[str, None, None]:
57
"""
58
Build distributions and yield paths to built files.
59
60
Args:
61
directory: Output directory for built distributions (default: "dist")
62
versions: List of version types to build
63
hooks_only: Whether to run only build hooks
64
clean: Whether to clean build directory before building
65
clean_hooks_after: Whether to clean hooks after building
66
clean_only: Whether to only clean without building
67
68
Yields:
69
str: Paths to built distribution files
70
"""
71
72
def get_version_api(self) -> dict[str, Callable]:
73
"""
74
Get version API information for this builder.
75
76
Returns:
77
dict: Version API information
78
"""
79
80
def iter_build_targets(self, versions: list[str]) -> Iterator[tuple[str, str]]:
81
"""
82
Iterate over build targets for given versions.
83
84
Args:
85
versions: List of version types
86
87
Yields:
88
tuple[str, str]: (version, target_name) pairs
89
"""
90
```
91
92
### Build Hook Interface
93
94
Abstract base class for build hooks that customize the build process.
95
96
```python { .api }
97
class BuildHookInterface(Generic[BuilderConfigBound]):
98
def clean(self, versions: list[str]) -> None:
99
"""
100
Clean up build artifacts for specified versions.
101
102
Args:
103
versions: List of version types to clean
104
"""
105
106
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
107
"""
108
Initialize hook before building.
109
110
Args:
111
version: Version being built
112
build_data: Build data dictionary
113
"""
114
115
def finalize(self, version: str, build_data: dict[str, Any], artifact_path: str) -> None:
116
"""
117
Finalize hook after building.
118
119
Args:
120
version: Version that was built
121
build_data: Build data dictionary
122
artifact_path: Path to built artifact
123
"""
124
```
125
126
### Version Source Interface
127
128
Abstract base class for version source plugins that determine project versions.
129
130
```python { .api }
131
class VersionSourceInterface(ABC):
132
def get_version_data(self) -> dict:
133
"""
134
Get the current version data.
135
136
Returns:
137
dict: Dictionary with 'version' key and current version string
138
"""
139
140
def set_version(self, version: str, version_data: dict) -> None:
141
"""
142
Set the version.
143
144
Args:
145
version: Version string to set
146
"""
147
```
148
149
### Version Scheme Interface
150
151
Abstract base class for version scheme plugins that manipulate version strings.
152
153
```python { .api }
154
class VersionSchemeInterface(ABC):
155
def update(self, version: str, **kwargs) -> str:
156
"""
157
Update a version string.
158
159
Args:
160
version: Version string to update
161
**kwargs: Additional update parameters
162
163
Returns:
164
str: Updated version string
165
"""
166
167
def parse(self, version: str) -> dict:
168
"""
169
Parse a version string into components.
170
171
Args:
172
version: Version string to parse
173
174
Returns:
175
dict: Version components
176
"""
177
178
def normalize(self, version: str) -> str:
179
"""
180
Normalize a version string.
181
182
Args:
183
version: Version string to normalize
184
185
Returns:
186
str: Normalized version string
187
"""
188
```
189
190
### Metadata Hook Interface
191
192
Abstract base class for metadata hook plugins that modify project metadata.
193
194
```python { .api }
195
class MetadataHookInterface(ABC):
196
def update(self, metadata: dict[str, Any]) -> None:
197
"""
198
Update project metadata.
199
200
Args:
201
metadata: Metadata dictionary to modify
202
"""
203
```
204
205
## Built-in Plugin Implementations
206
207
### Version Sources
208
209
Built-in version source implementations for common version management patterns.
210
211
```python { .api }
212
class CodeSource(VersionSourceInterface):
213
"""Extract version from Python code using AST parsing."""
214
215
class RegexSource(VersionSourceInterface):
216
"""Extract version using regular expression patterns."""
217
218
class EnvSource(VersionSourceInterface):
219
"""Get version from environment variables."""
220
```
221
222
### Version Schemes
223
224
```python { .api }
225
class StandardScheme(VersionSchemeInterface):
226
"""Standard PEP 440 compliant version scheme."""
227
```
228
229
### Build Hooks
230
231
```python { .api }
232
class VersionBuildHook(BuildHookInterface):
233
"""Hook for managing version information during builds."""
234
235
class CustomBuildHook:
236
"""Custom user-defined build hook loaded from scripts."""
237
```
238
239
### Metadata Hooks
240
241
```python { .api }
242
class CustomMetadataHook:
243
"""Custom user-defined metadata hook loaded from scripts."""
244
```
245
246
## Plugin Registration
247
248
### Registration Functions
249
250
Functions for registering built-in plugins.
251
252
```python { .api }
253
def hatch_register_builder() -> list[type[BuilderInterface]]:
254
"""Register built-in builder plugins."""
255
256
def hatch_register_build_hook() -> list[type[BuildHookInterface]]:
257
"""Register built-in build hook plugins."""
258
```
259
260
### Plugin Entry Points
261
262
Plugins are discovered through entry points in setup.py or pyproject.toml:
263
264
```toml
265
[project.entry-points.hatch_builder]
266
my_builder = "my_package.builders:MyBuilder"
267
268
[project.entry-points.hatch_build_hook]
269
my_hook = "my_package.hooks:MyBuildHook"
270
271
[project.entry-points.hatch_version_source]
272
my_source = "my_package.version:MyVersionSource"
273
274
[project.entry-points.hatch_version_scheme]
275
my_scheme = "my_package.version:MyVersionScheme"
276
277
[project.entry-points.hatch_metadata_hook]
278
my_metadata = "my_package.metadata:MyMetadataHook"
279
```
280
281
## Plugin Development
282
283
### Creating Custom Builders
284
285
```python
286
from hatchling.builders.plugin.interface import BuilderInterface
287
288
class MyBuilder(BuilderInterface):
289
PLUGIN_NAME = "my-builder"
290
291
def build(self, *, directory="dist", versions=None):
292
# Custom build logic
293
yield self.create_my_distribution(directory)
294
295
def get_version_api(self):
296
return {"my-version": "1.0"}
297
```
298
299
### Creating Build Hooks
300
301
```python
302
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
303
304
class MyBuildHook(BuildHookInterface):
305
PLUGIN_NAME = "my-hook"
306
307
def initialize(self, version, build_data):
308
# Pre-build customization
309
build_data["custom_setting"] = "value"
310
311
def finalize(self, version, build_data, artifact_path):
312
# Post-build customization
313
print(f"Built {artifact_path}")
314
```
315
316
### Creating Version Sources
317
318
```python
319
from hatchling.version.source.plugin.interface import VersionSourceInterface
320
321
class MyVersionSource(VersionSourceInterface):
322
PLUGIN_NAME = "my-source"
323
324
def get_version_data(self):
325
# Custom version retrieval logic
326
return {"version": "1.0.0"}
327
328
def set_version(self, version, version_data):
329
# Custom version setting logic
330
pass
331
```
332
333
## Plugin Configuration
334
335
Plugins are configured in pyproject.toml:
336
337
```toml
338
[tool.hatch.build]
339
builder = "my-builder"
340
hooks = ["my-hook"]
341
342
[tool.hatch.version]
343
source = "my-source"
344
scheme = "my-scheme"
345
346
[tool.hatch.metadata.hooks.my-metadata]
347
setting = "value"
348
```
349
350
## Plugin Utilities
351
352
### Plugin Loading
353
354
```python { .api }
355
def load_plugin_from_script(
356
path: str,
357
script_name: str,
358
plugin_class: type[T],
359
plugin_id: str
360
) -> type[T]:
361
"""
362
Load a plugin class from a Python script.
363
364
Args:
365
path: Path to script file
366
script_name: Name of the script
367
plugin_class: Expected plugin base class
368
plugin_id: Plugin identifier
369
370
Returns:
371
type[T]: Loaded plugin class
372
"""
373
```
374
375
### Plugin Management Classes
376
377
```python { .api }
378
class ClassRegister:
379
"""Registry for plugin classes with validation."""
380
381
class ThirdPartyPlugins:
382
"""Manager for third-party plugin discovery and loading."""
383
```
384
385
## Error Handling
386
387
```python { .api }
388
class UnknownPluginError(ValueError):
389
"""Raised when referencing an unknown plugin."""
390
```
391
392
## Usage Examples
393
394
### Using Plugin Manager
395
396
```python
397
from hatchling.metadata.core import ProjectMetadata
398
from hatchling.plugin.manager import PluginManager
399
400
# Create plugin manager
401
plugin_manager = PluginManager()
402
403
# List available plugins
404
print("Builders:", list(plugin_manager.builders.keys()))
405
print("Build hooks:", list(plugin_manager.build_hooks.keys()))
406
print("Version sources:", list(plugin_manager.version_sources.keys()))
407
print("Version schemes:", list(plugin_manager.version_schemes.keys()))
408
print("Metadata hooks:", list(plugin_manager.metadata_hooks.keys()))
409
410
# Get specific plugin
411
wheel_builder = plugin_manager.builders["wheel"]
412
standard_scheme = plugin_manager.version_schemes["standard"]
413
```
414
415
### Using Plugins in Configuration
416
417
```python
418
# Configure builder with plugins
419
from hatchling.builders.wheel import WheelBuilder
420
421
builder = WheelBuilder(
422
root=os.getcwd(),
423
plugin_manager=plugin_manager,
424
config={
425
"hooks": ["version", "my-custom-hook"],
426
"version-source": "code",
427
"version-scheme": "standard"
428
}
429
)
430
```
431
432
### Plugin Registration
433
434
Third-party plugins can be registered using hatchling's plugin system.
435
436
```python { .api }
437
from hatchling.plugin import hookimpl
438
439
@hookimpl
440
def hatch_register_builder():
441
"""Register a custom builder plugin."""
442
return MyBuilderClass
443
444
@hookimpl
445
def hatch_register_version_source():
446
"""Register a custom version source plugin."""
447
return MyVersionSourceClass
448
449
@hookimpl
450
def hatch_register_version_scheme():
451
"""Register a custom version scheme plugin."""
452
return MyVersionSchemeClass
453
454
@hookimpl
455
def hatch_register_metadata_hook():
456
"""Register a custom metadata hook plugin."""
457
return MyMetadataHookClass
458
459
@hookimpl
460
def hatch_register_build_hook():
461
"""Register a custom build hook plugin."""
462
return MyBuildHookClass
463
```
464
465
#### Usage Example
466
467
```python
468
# plugin.py
469
from hatchling.plugin import hookimpl
470
from hatchling.builders.plugin.interface import BuilderInterface
471
472
class CustomBuilder(BuilderInterface):
473
PLUGIN_NAME = 'custom'
474
475
def get_version_api(self):
476
return {'standard': self.build_standard}
477
478
def build_standard(self, directory, **build_data):
479
# Custom build logic
480
pass
481
482
@hookimpl
483
def hatch_register_builder():
484
return CustomBuilder
485
```
486
487
The plugin system makes hatchling highly extensible, allowing custom build logic, version management, and metadata processing to be implemented as reusable plugins.