super-solid-system 1.0.0__tar.gz → 1.0.2__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.
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/PKG-INFO +13 -42
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/README.md +439 -468
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/pyproject.toml +55 -55
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/LICENSE +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/__init__.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/__init__.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/discovery.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/engine.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/events.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/health.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/registry.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/security.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/core/system.py +0 -0
- {super_solid_system-1.0.0 → super_solid_system-1.0.2}/supersolid/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: super-solid-system
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: A lightweight, type-safe microkernel & plug-and-play framework for Python.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -18,15 +18,13 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
20
|
Requires-Dist: pydantic (>=2.0.0)
|
|
21
|
-
Project-URL: Homepage, https://github.com/
|
|
22
|
-
Project-URL: Issues, https://github.com/
|
|
23
|
-
Project-URL: Repository, https://github.com/
|
|
21
|
+
Project-URL: Homepage, https://github.com/super-solid-framework/super-solid-system
|
|
22
|
+
Project-URL: Issues, https://github.com/super-solid-framework/super-solid-system/issues
|
|
23
|
+
Project-URL: Repository, https://github.com/super-solid-framework/super-solid-system
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
|
|
26
|
-
# Super-Solid System (`supersolid`)
|
|
27
|
-
|
|
28
26
|
<p align="center">
|
|
29
|
-
<img src="docs/logo.png" alt="Super-Solid" width="250"/>
|
|
27
|
+
<img src="https://raw.githubusercontent.com/super-solid-framework/super-solid-system/main/docs/logo.png" alt="Super-Solid" width="250"/>
|
|
30
28
|
</p>
|
|
31
29
|
|
|
32
30
|
<h1 align="center">Super-Solid System</h1>
|
|
@@ -40,7 +38,7 @@ Description-Content-Type: text/markdown
|
|
|
40
38
|
<img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-green"/>
|
|
41
39
|
<img alt="Tests" src="https://img.shields.io/badge/tests-43%2F43%20passing-brightgreen"/>
|
|
42
40
|
<img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"/>
|
|
43
|
-
<img alt="Status" src="https://img.shields.io/badge/status-v1.0.
|
|
41
|
+
<img alt="Status" src="https://img.shields.io/badge/status-v1.0.2-brightgreen"/>
|
|
44
42
|
</p>
|
|
45
43
|
|
|
46
44
|
> A lightweight, type-safe microkernel & plug-and-play framework for Python.
|
|
@@ -60,31 +58,9 @@ No magic, no hidden state, no framework lock-in. Just clean abstractions you sub
|
|
|
60
58
|
|
|
61
59
|
## Architecture
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
EB["SuperSolidEventBus"]
|
|
67
|
-
E1["SuperSolidEngine A"]
|
|
68
|
-
E2["SuperSolidEngine B"]
|
|
69
|
-
R1["SuperSolidRegistry 1"]
|
|
70
|
-
R2["SuperSolidRegistry 2"]
|
|
71
|
-
R3["SuperSolidRegistry 3"]
|
|
72
|
-
D["DiscoveryStrategy Chain"]
|
|
73
|
-
SP["SecurityPolicy"]
|
|
74
|
-
H["HealthCheckable"]
|
|
75
|
-
|
|
76
|
-
S -->|starts / stops| E1
|
|
77
|
-
S -->|starts / stops| E2
|
|
78
|
-
S -->|publishes signals| EB
|
|
79
|
-
E1 -->|routes loads to| R1
|
|
80
|
-
E1 -->|routes loads to| R2
|
|
81
|
-
E2 -->|routes loads to| R3
|
|
82
|
-
R1 -->|discovers plugins via| D
|
|
83
|
-
R1 -.->|enforced by| SP
|
|
84
|
-
R2 -.->|enforced by| SP
|
|
85
|
-
E1 -.->|implements| H
|
|
86
|
-
E2 -.->|implements| H
|
|
87
|
-
```
|
|
61
|
+
<p align="center">
|
|
62
|
+
<img src="https://raw.githubusercontent.com/super-solid-framework/super-solid-system/main/docs/architecture.svg" alt="Architecture Diagram" width="700"/>
|
|
63
|
+
</p>
|
|
88
64
|
|
|
89
65
|
The core loop is simple:
|
|
90
66
|
|
|
@@ -329,14 +305,9 @@ event.model_dump_json()
|
|
|
329
305
|
|
|
330
306
|
When you call `registry.load()` for something that isn't registered yet, the registry runs a **discovery chain** to try to find it automatically. The default chain has three strategies:
|
|
331
307
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
B -->|not found| C["PluginDirectory"]
|
|
336
|
-
style A fill:#4a9,stroke:#333,color:#fff
|
|
337
|
-
style B fill:#49a,stroke:#333,color:#fff
|
|
338
|
-
style C fill:#a94,stroke:#333,color:#fff
|
|
339
|
-
```
|
|
308
|
+
<p align="center">
|
|
309
|
+
<img src="https://raw.githubusercontent.com/super-solid-framework/super-solid-system/main/docs/discovery.svg" alt="Discovery Chain Diagram" width="550"/>
|
|
310
|
+
</p>
|
|
340
311
|
|
|
341
312
|
| Strategy | Where it looks |
|
|
342
313
|
| :---------------- | :------------------------------------------------------------------------ |
|
|
@@ -490,5 +461,5 @@ TOTAL 438 0 100%
|
|
|
490
461
|
|
|
491
462
|
## License
|
|
492
463
|
|
|
493
|
-
[Apache-2.0](LICENSE)
|
|
464
|
+
[Apache-2.0](https://github.com/super-solid-framework/super-solid-system/blob/main/LICENSE)
|
|
494
465
|
|
|
@@ -1,468 +1,439 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
</
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
<img alt="
|
|
15
|
-
<img alt="
|
|
16
|
-
<img alt="
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
##
|
|
71
|
-
|
|
72
|
-
###
|
|
73
|
-
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
```python
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```python
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```python
|
|
178
|
-
from supersolid.core import
|
|
179
|
-
|
|
180
|
-
class
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
## Running Tests
|
|
441
|
-
|
|
442
|
-
Run the test suite with coverage report:
|
|
443
|
-
|
|
444
|
-
```bash
|
|
445
|
-
poetry run python -m pytest --cov=supersolid --cov-report=term-missing
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
```text
|
|
449
|
-
Name Stmts Miss Cover
|
|
450
|
-
--------------------------------------------------
|
|
451
|
-
supersolid/__init__.py 2 0 100%
|
|
452
|
-
supersolid/core/__init__.py 8 0 100%
|
|
453
|
-
supersolid/core/discovery.py 43 0 100%
|
|
454
|
-
supersolid/core/engine.py 49 0 100%
|
|
455
|
-
supersolid/core/events.py 85 0 100%
|
|
456
|
-
supersolid/core/health.py 14 0 100%
|
|
457
|
-
supersolid/core/registry.py 154 0 100%
|
|
458
|
-
supersolid/core/security.py 24 0 100%
|
|
459
|
-
supersolid/core/system.py 59 0 100%
|
|
460
|
-
--------------------------------------------------
|
|
461
|
-
TOTAL 438 0 100%
|
|
462
|
-
|
|
463
|
-
============================= 43 passed in 1.12s ==============================
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
## License
|
|
467
|
-
|
|
468
|
-
[Apache-2.0](LICENSE)
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/super-solid-framework/super-solid-system/main/docs/logo.png" alt="Super-Solid" width="250"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Super-Solid System</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>A robust, generic infrastructure for building modular software systems with plug-and-play engines, dynamic plugin discovery, thread-safe component registries, and fault-tolerant system lifecycle management.</strong><br/>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img alt="Python" src="https://img.shields.io/badge/python-%3E%3D3.10-blue?logo=python&logoColor=white"/>
|
|
13
|
+
<img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-green"/>
|
|
14
|
+
<img alt="Tests" src="https://img.shields.io/badge/tests-43%2F43%20passing-brightgreen"/>
|
|
15
|
+
<img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"/>
|
|
16
|
+
<img alt="Status" src="https://img.shields.io/badge/status-v1.0.2-brightgreen"/>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
> A lightweight, type-safe microkernel & plug-and-play framework for Python.
|
|
20
|
+
|
|
21
|
+
## What is Super-Solid System?
|
|
22
|
+
|
|
23
|
+
Super-Solid System (`S³`) gives you a small set of building blocks for assembling modular applications:
|
|
24
|
+
|
|
25
|
+
- **Registries** hold your components — type-checked, thread-safe, and cached.
|
|
26
|
+
- **Engines** group registries together and handle boot/shutdown logic.
|
|
27
|
+
- **Systems** orchestrate engines in dependency order with automatic rollback.
|
|
28
|
+
- **Events** let everything talk to each other through a reactive signal bus.
|
|
29
|
+
- **Security** controls who can load what and from where.
|
|
30
|
+
- **Health** provides a standard way for components to report their status.
|
|
31
|
+
|
|
32
|
+
No magic, no hidden state, no framework lock-in. Just clean abstractions you subclass and wire up.
|
|
33
|
+
|
|
34
|
+
## Architecture
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="https://raw.githubusercontent.com/super-solid-framework/super-solid-system/main/docs/architecture.svg" alt="Architecture Diagram" width="700"/>
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
The core loop is simple:
|
|
41
|
+
|
|
42
|
+
1. **Register** component classes into typed registries (or let discovery find them).
|
|
43
|
+
2. **Load** components on demand — the registry instantiates, caches, and returns them.
|
|
44
|
+
3. **Wire** registries into engines, engines into a system, and call `start()`.
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
### Pip (editable, for development)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install -e /path/to/super-solid-system
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Poetry (as a local dependency)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
poetry add --editable /path/to/super-solid-system
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Docker (Multi-stage build)
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Build the production Docker image
|
|
64
|
+
docker build -t super-solid-system:latest .
|
|
65
|
+
|
|
66
|
+
# Run container & verify installation
|
|
67
|
+
docker run --rm super-solid-system:latest
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Quickstart
|
|
71
|
+
|
|
72
|
+
### 1. Define a base interface and a registry
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from abc import ABC, abstractmethod
|
|
76
|
+
from supersolid.core import super_solid_registry, SuperSolidRegistry
|
|
77
|
+
|
|
78
|
+
class BaseAdapter(ABC):
|
|
79
|
+
@abstractmethod
|
|
80
|
+
def connect(self) -> None: ...
|
|
81
|
+
|
|
82
|
+
# [QUICK] Create a typed component registry using super_solid_registry
|
|
83
|
+
Adapters = super_solid_registry(name="adapters", component_class=BaseAdapter)
|
|
84
|
+
|
|
85
|
+
# [ALTERNATIVE] Create a class component registry by subclassing SuperSolidRegistry
|
|
86
|
+
class AdapterRegistry(SuperSolidRegistry[BaseAdapter]):
|
|
87
|
+
def __init__(self):
|
|
88
|
+
super().__init__(name="adapters", component_class=BaseAdapter)
|
|
89
|
+
|
|
90
|
+
Adapters = AdapterRegistry()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`SuperSolidRegistry` is generic — it enforces that only `BaseAdapter` subclasses can be registered here. Anything else raises a `TypeError` at registration time.
|
|
94
|
+
|
|
95
|
+
### 2. Register components
|
|
96
|
+
|
|
97
|
+
You can register manually:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
Adapters.register("database", "sqlite", SqliteAdapter)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or use the `@super_solid_component` decorator for a more declarative style:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from supersolid.core import super_solid_component
|
|
107
|
+
|
|
108
|
+
@super_solid_component(Adapters, namespace="database", name="postgres", version="1.0.0")
|
|
109
|
+
class PostgresAdapter(BaseAdapter):
|
|
110
|
+
def __init__(self, dsn: str = "postgresql://localhost/db"):
|
|
111
|
+
self.dsn = dsn
|
|
112
|
+
|
|
113
|
+
def connect(self) -> None:
|
|
114
|
+
print(f"Connected to {self.dsn}")
|
|
115
|
+
|
|
116
|
+
def disconnect(self) -> None:
|
|
117
|
+
print("Disconnected.")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The decorator registers the class and attaches a `ComponentMetadata` model you can inspect later:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
PostgresAdapter._metadata.version # "1.0.0"
|
|
124
|
+
PostgresAdapter._metadata.namespace # "database"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 3. Load components
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
db = Adapters.load("database", "postgres", dsn="postgresql://prod/mydb")
|
|
131
|
+
db.connect() # Connected to postgresql://prod/mydb
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
What happens under the hood:
|
|
135
|
+
|
|
136
|
+
1. Checks the cache — if already loaded with the same parameters, returns the cached instance.
|
|
137
|
+
2. If not registered, runs the **discovery chain** (more on that below).
|
|
138
|
+
3. Introspects the constructor signature and filters keyword arguments automatically.
|
|
139
|
+
4. Calls lifecycle hooks (`initialize()` or `boot()`) if the component defines them.
|
|
140
|
+
5. Caches and returns the instance.
|
|
141
|
+
|
|
142
|
+
When you're done:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
Adapters.unload("database", "postgres")
|
|
146
|
+
# Calls disconnect() or stop() automatically if the component defines them
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 4. Build an engine
|
|
150
|
+
|
|
151
|
+
A `SuperSolidEngine` groups registries and provides a unified loading interface:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from supersolid.core import SuperSolidEngine
|
|
155
|
+
|
|
156
|
+
class CoreEngine(SuperSolidEngine):
|
|
157
|
+
def __init__(self):
|
|
158
|
+
super().__init__()
|
|
159
|
+
self.connect(Adapters) # attach registries
|
|
160
|
+
|
|
161
|
+
def boot(self, **kwargs) -> None:
|
|
162
|
+
self._running = True
|
|
163
|
+
db = self.load("adapters", "database", "postgres")
|
|
164
|
+
db.connect()
|
|
165
|
+
|
|
166
|
+
def mount(self, app, **kwargs) -> None:
|
|
167
|
+
pass # hook for attaching to a web framework, etc.
|
|
168
|
+
|
|
169
|
+
def shutdown(self, **kwargs) -> None:
|
|
170
|
+
self._running = False
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Need async? Subclass `SuperSolidAsyncEngine` instead — it provides `boot_async()`, `mount_async()`, and `shutdown_async()` that automatically bridge to the sync interface via `asyncio.run()`.
|
|
174
|
+
|
|
175
|
+
### 5. Orchestrate with a system
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from supersolid.core import SuperSolidSystem
|
|
179
|
+
|
|
180
|
+
class MyApp(SuperSolidSystem):
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
app = MyApp()
|
|
184
|
+
app.add_engine("core", CoreEngine())
|
|
185
|
+
app.start() # boots engines in dependency order
|
|
186
|
+
# ... your app runs ...
|
|
187
|
+
app.stop() # shuts down in reverse order
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
If any engine fails during `start()`, all previously booted engines are shut down in reverse (LIFO) order automatically.
|
|
191
|
+
|
|
192
|
+
## Engine Dependencies (Dependency Resolution)
|
|
193
|
+
|
|
194
|
+
Engines can declare dependencies on other engines:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
class ConsensusEngine(SuperSolidEngine):
|
|
198
|
+
depends_on = ["network"] # boot network engine first
|
|
199
|
+
# ...
|
|
200
|
+
|
|
201
|
+
class NetworkEngine(SuperSolidEngine):
|
|
202
|
+
depends_on = []
|
|
203
|
+
# ...
|
|
204
|
+
|
|
205
|
+
system = MyApp()
|
|
206
|
+
system.add_engine("consensus", ConsensusEngine())
|
|
207
|
+
system.add_engine("network", NetworkEngine())
|
|
208
|
+
system.start()
|
|
209
|
+
# Boot order: network → consensus (resolved via topological sort)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The system uses the internal `graphlibs` `TopologicalSorter` so circular dependencies raise a `CycleError` immediately.
|
|
213
|
+
|
|
214
|
+
## Events
|
|
215
|
+
|
|
216
|
+
`SuperSolidSystem` comes with a built-in `SuperSolidEventBus` that publishes lifecycle signals automatically:
|
|
217
|
+
|
|
218
|
+
| Event | When it fires |
|
|
219
|
+
| :-------------------- | :--------------------------------- |
|
|
220
|
+
| `EngineBootingEvent` | Right before an engine boots |
|
|
221
|
+
| `EngineBootedEvent` | After an engine boots successfully |
|
|
222
|
+
| `EngineShutdownEvent` | After an engine shuts down |
|
|
223
|
+
| `SystemErrorEvent` | On boot failure or shutdown error |
|
|
224
|
+
| `PluginLoadedEvent` | When a plugin is loaded |
|
|
225
|
+
|
|
226
|
+
### Subscribing to events
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from supersolid.core import SuperSolidEventBus, EngineBootedEvent, super_solid_subscriber
|
|
230
|
+
|
|
231
|
+
bus = SuperSolidEventBus()
|
|
232
|
+
|
|
233
|
+
@super_solid_subscriber(bus)
|
|
234
|
+
def on_boot(event: EngineBootedEvent):
|
|
235
|
+
print(f"Engine '{event.engine_name}' is up!")
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The decorator infers the event type from the parameter annotation. You can also be explicit:
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
@super_solid_subscriber(bus, event_type=EngineBootedEvent)
|
|
242
|
+
def on_boot(event):
|
|
243
|
+
print(f"Engine '{event.engine_name}' is up!")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Publishing events
|
|
247
|
+
|
|
248
|
+
The `@super_solid_publisher` decorator auto-publishes a function's return value if it's a `SystemEvent`:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from supersolid.core import super_solid_publisher, EngineBootedEvent
|
|
252
|
+
|
|
253
|
+
@super_solid_publisher(bus)
|
|
254
|
+
def finish_boot(name: str) -> EngineBootedEvent:
|
|
255
|
+
# ... do boot work ...
|
|
256
|
+
return EngineBootedEvent(engine_name=name)
|
|
257
|
+
|
|
258
|
+
finish_boot("consensus") # automatically published to bus
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Works with both sync and async functions.
|
|
262
|
+
|
|
263
|
+
### Custom events
|
|
264
|
+
|
|
265
|
+
All events are Pydantic models with `extra = "allow"`, so you can add any fields:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from supersolid.core import SystemEvent
|
|
269
|
+
|
|
270
|
+
class NodeSyncEvent(SystemEvent):
|
|
271
|
+
node_id: str
|
|
272
|
+
epoch: int
|
|
273
|
+
|
|
274
|
+
# Extra fields work too — they serialize to JSON just fine
|
|
275
|
+
event = NodeSyncEvent(node_id="node_01", epoch=42, custom_field="whatever")
|
|
276
|
+
event.model_dump_json()
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Plugin Discovery
|
|
280
|
+
|
|
281
|
+
When you call `registry.load()` for something that isn't registered yet, the registry runs a **discovery chain** to try to find it automatically. The default chain has three strategies:
|
|
282
|
+
|
|
283
|
+
<p align="center">
|
|
284
|
+
<img src="https://raw.githubusercontent.com/super-solid-framework/super-solid-system/main/docs/discovery.svg" alt="Discovery Chain Diagram" width="550"/>
|
|
285
|
+
</p>
|
|
286
|
+
|
|
287
|
+
| Strategy | Where it looks |
|
|
288
|
+
| :---------------- | :------------------------------------------------------------------------ |
|
|
289
|
+
| `InternalLib` | `{root_pkg}.lib.{registry_name}.{namespace}_{name}` (trusted imports) |
|
|
290
|
+
| `EntryPoints` | Setuptools entry points in group `{root_pkg}.{registry_name}.{namespace}` |
|
|
291
|
+
| `PluginDirectory` | `plugins.{registry_name}.{namespace}_{name}` (local files) |
|
|
292
|
+
|
|
293
|
+
### Writing a custom discovery strategy
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from supersolid.core import DiscoveryStrategy
|
|
297
|
+
|
|
298
|
+
class RemoteDiscovery(DiscoveryStrategy):
|
|
299
|
+
def discover(self, registry, item_namespace, item_name) -> bool:
|
|
300
|
+
# fetch plugin from remote source, register it
|
|
301
|
+
return registry.is_registered(item_namespace, item_name)
|
|
302
|
+
|
|
303
|
+
Adapters.add_discovery(RemoteDiscovery())
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Security
|
|
307
|
+
|
|
308
|
+
### SecurityPolicy
|
|
309
|
+
|
|
310
|
+
Attach a `SecurityPolicy` to any registry to control access:
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
from supersolid.core import SecurityPolicy
|
|
314
|
+
|
|
315
|
+
policy = SecurityPolicy(
|
|
316
|
+
allowed_namespaces={"database", "cache"}, # only these namespaces can be loaded
|
|
317
|
+
allowed_callers={"core_engine"}, # only these caller IDs are authorized
|
|
318
|
+
allow_internal_lib=True, # trusted internal imports still work
|
|
319
|
+
allow_dynamic_discovery=False, # block external plugins (EntryPoints, PluginDirectory)
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
Adapters.set_policy(policy)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Now `Adapters.load("auth", "oauth")` raises `PermissionError` because `"auth"` isn't in the allowed set. And external discovery strategies are skipped entirely, while `InternalLib` still runs as a trusted fallback.
|
|
326
|
+
|
|
327
|
+
### Plugin verification
|
|
328
|
+
|
|
329
|
+
Before importing a plugin file, you can verify its checksum:
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
from supersolid.core import PluginVerifier
|
|
333
|
+
|
|
334
|
+
if PluginVerifier.verify_sha256("plugins/consensus/my_plugin.py", expected_hash):
|
|
335
|
+
import plugins.consensus.my_plugin
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Health Checks
|
|
339
|
+
|
|
340
|
+
Any component can implement health reporting by defining a `health_check()` method:
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
from supersolid.core import HealthStatus, HealthState, HealthCheckable
|
|
344
|
+
|
|
345
|
+
class DatabaseAdapter:
|
|
346
|
+
def health_check(self) -> HealthStatus:
|
|
347
|
+
return HealthStatus(
|
|
348
|
+
state=HealthState.HEALTHY,
|
|
349
|
+
details={"connections": 42, "pool_size": 100}
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
db = DatabaseAdapter()
|
|
353
|
+
isinstance(db, HealthCheckable) # True — structural typing via Protocol
|
|
354
|
+
db.health_check().model_dump_json()
|
|
355
|
+
# {"state": "healthy", "details": {"connections": 42, "pool_size": 100}, "timestamp": ...}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
`HealthCheckable` is a `@runtime_checkable` Protocol — no need to inherit from anything.
|
|
359
|
+
|
|
360
|
+
The three states are `HEALTHY`, `DEGRADED`, and `UNHEALTHY`.
|
|
361
|
+
|
|
362
|
+
## Project Structure
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
super-solid-system/
|
|
366
|
+
├── supersolid/
|
|
367
|
+
│ └── core/
|
|
368
|
+
│ ├── __init__.py # Public API exports
|
|
369
|
+
│ ├── registry.py # SuperSolidRegistry, super_solid_component, ComponentMetadata
|
|
370
|
+
│ ├── engine.py # SuperSolidEngine, AsyncSuperSolidEngine
|
|
371
|
+
│ ├── system.py # SuperSolidSystem (orchestrator)
|
|
372
|
+
│ ├── events.py # SuperSolidEventBus, SystemEvent, super_solid_subscriber, super_solid_publisher
|
|
373
|
+
│ ├── discovery.py # DiscoveryStrategy, InternalLib, EntryPoints, PluginDirectory
|
|
374
|
+
│ ├── security.py # SecurityPolicy, PluginVerifier
|
|
375
|
+
│ └── health.py # HealthStatus, HealthState, HealthCheckable
|
|
376
|
+
├── tests/
|
|
377
|
+
│ ├── test_registry.py # Registration, loading, type enforcement, thread safety, unload
|
|
378
|
+
│ ├── test_events.py # Event bus pub/sub, @open_subscriber, @open_publisher
|
|
379
|
+
│ ├── test_security.py # Namespace ACL, caller auth, discovery fallbacks, SHA-256
|
|
380
|
+
│ ├── test_health.py # Health models, Protocol duck typing
|
|
381
|
+
│ └── test_system.py # DAG resolution, start/stop, rollback on failure
|
|
382
|
+
├── pyproject.toml
|
|
383
|
+
├── LICENSE
|
|
384
|
+
└── README.md
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## API Reference
|
|
390
|
+
|
|
391
|
+
| Export | Module | What it does |
|
|
392
|
+
| :----------------------- | :--------------- | :----------------------------------------------------------------------------------------------- |
|
|
393
|
+
| `SuperSolidSystem` | `core.system` | Orchestrator — boots/stops engines in dependency order (`SolidSystem`, `OpenSystem`) |
|
|
394
|
+
| `SuperSolidEngine` | `core.engine` | Domain hub — groups registries, handles boot/mount/shutdown (`SolidEngine`, `OpenEngine`) |
|
|
395
|
+
| `SuperSolidAsyncEngine` | `core.engine` | Async variant supporting `boot_async()`, `mount_async()` (`SolidAsyncEngine`, `AsyncOpenEngine`) |
|
|
396
|
+
| `SuperSolidRegistry` | `core.registry` | Generic registry — type checks, caching, discovery (`SolidRegistry`, `OpenRegistry`) |
|
|
397
|
+
| `super_solid_registry` | `core.registry` | Factory function — instantiates a `SuperSolidRegistry` (`solid_registry`, `open_registry`) |
|
|
398
|
+
| `super_solid_component` | `core.registry` | Decorator — registers a class with metadata (`solid_component`, `open_component`) |
|
|
399
|
+
| `ComponentMetadata` | `core.registry` | Pydantic model — name, namespace, version, and extras |
|
|
400
|
+
| `SuperSolidEventBus` | `core.events` | In-memory pub/sub signal bus (`SolidEventBus`, `OpenEventBus`) |
|
|
401
|
+
| `SystemEvent` | `core.events` | Base event model (Pydantic, extra fields allowed) |
|
|
402
|
+
| `super_solid_subscriber` | `core.events` | Decorator — subscribes handler with type inference (`solid_subscriber`, `open_subscriber`) |
|
|
403
|
+
| `super_solid_publisher` | `core.events` | Decorator — auto-publishes return values (`solid_publisher`, `open_publisher`) |
|
|
404
|
+
| `DiscoveryStrategy` | `core.discovery` | Abstract base — subclass to write custom plugin discovery |
|
|
405
|
+
| `SecurityPolicy` | `core.security` | Pydantic model — namespace/caller ACL, discovery toggles |
|
|
406
|
+
| `PluginVerifier` | `core.security` | SHA-256 file checksum verification |
|
|
407
|
+
| `HealthStatus` | `core.health` | Pydantic model — state, details, timestamp |
|
|
408
|
+
| `HealthState` | `core.health` | Enum — `HEALTHY`, `DEGRADED`, `UNHEALTHY` |
|
|
409
|
+
| `HealthCheckable` | `core.health` | Protocol — any class with `health_check()` satisfies it |
|
|
410
|
+
|
|
411
|
+
## Running Tests
|
|
412
|
+
|
|
413
|
+
Run the test suite with coverage report:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
poetry run python -m pytest --cov=supersolid --cov-report=term-missing
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
```text
|
|
420
|
+
Name Stmts Miss Cover
|
|
421
|
+
--------------------------------------------------
|
|
422
|
+
supersolid/__init__.py 2 0 100%
|
|
423
|
+
supersolid/core/__init__.py 8 0 100%
|
|
424
|
+
supersolid/core/discovery.py 43 0 100%
|
|
425
|
+
supersolid/core/engine.py 49 0 100%
|
|
426
|
+
supersolid/core/events.py 85 0 100%
|
|
427
|
+
supersolid/core/health.py 14 0 100%
|
|
428
|
+
supersolid/core/registry.py 154 0 100%
|
|
429
|
+
supersolid/core/security.py 24 0 100%
|
|
430
|
+
supersolid/core/system.py 59 0 100%
|
|
431
|
+
--------------------------------------------------
|
|
432
|
+
TOTAL 438 0 100%
|
|
433
|
+
|
|
434
|
+
============================= 43 passed in 1.12s ==============================
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## License
|
|
438
|
+
|
|
439
|
+
[Apache-2.0](https://github.com/super-solid-framework/super-solid-system/blob/main/LICENSE)
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "super-solid-system"
|
|
3
|
-
version = "1.0.
|
|
4
|
-
description = "A lightweight, type-safe microkernel & plug-and-play framework for Python."
|
|
5
|
-
authors = [
|
|
6
|
-
{name = "Doth-J", email = "theodjoan@gmail.com"}
|
|
7
|
-
]
|
|
8
|
-
license = "Apache-2.0"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.10"
|
|
11
|
-
keywords = [
|
|
12
|
-
"microkernel",
|
|
13
|
-
"plugin",
|
|
14
|
-
"registry",
|
|
15
|
-
"modular",
|
|
16
|
-
"framework",
|
|
17
|
-
"dependency-injection",
|
|
18
|
-
"type-safe",
|
|
19
|
-
]
|
|
20
|
-
classifiers = [
|
|
21
|
-
"Development Status :: 5 - Production/Stable",
|
|
22
|
-
"Intended Audience :: Developers",
|
|
23
|
-
"Programming Language :: Python :: 3",
|
|
24
|
-
"Programming Language :: Python :: 3.10",
|
|
25
|
-
"Programming Language :: Python :: 3.11",
|
|
26
|
-
"Programming Language :: Python :: 3.12",
|
|
27
|
-
"Programming Language :: Python :: 3.13",
|
|
28
|
-
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
29
|
-
"Typing :: Typed",
|
|
30
|
-
]
|
|
31
|
-
dependencies = [
|
|
32
|
-
"pydantic (>=2.0.0)"
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
[project.urls]
|
|
36
|
-
Homepage = "https://github.com/
|
|
37
|
-
Repository = "https://github.com/
|
|
38
|
-
Issues = "https://github.com/
|
|
39
|
-
|
|
40
|
-
[tool.poetry]
|
|
41
|
-
packages = [{include = "supersolid"}]
|
|
42
|
-
|
|
43
|
-
[build-system]
|
|
44
|
-
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
45
|
-
build-backend = "poetry.core.masonry.api"
|
|
46
|
-
|
|
47
|
-
[dependency-groups]
|
|
48
|
-
test = [
|
|
49
|
-
"pytest (>=9.1.1,<10.0.0)",
|
|
50
|
-
"pytest-cov (>=5.0.0,<7.0.0)"
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
[tool.pytest.ini_options]
|
|
54
|
-
testpaths = ["tests"]
|
|
55
|
-
addopts = "--cov=supersolid --cov-report=term-missing"
|
|
1
|
+
[project]
|
|
2
|
+
name = "super-solid-system"
|
|
3
|
+
version = "1.0.2"
|
|
4
|
+
description = "A lightweight, type-safe microkernel & plug-and-play framework for Python."
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "Doth-J", email = "theodjoan@gmail.com"}
|
|
7
|
+
]
|
|
8
|
+
license = "Apache-2.0"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
keywords = [
|
|
12
|
+
"microkernel",
|
|
13
|
+
"plugin",
|
|
14
|
+
"registry",
|
|
15
|
+
"modular",
|
|
16
|
+
"framework",
|
|
17
|
+
"dependency-injection",
|
|
18
|
+
"type-safe",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 5 - Production/Stable",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"pydantic (>=2.0.0)"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/super-solid-framework/super-solid-system"
|
|
37
|
+
Repository = "https://github.com/super-solid-framework/super-solid-system"
|
|
38
|
+
Issues = "https://github.com/super-solid-framework/super-solid-system/issues"
|
|
39
|
+
|
|
40
|
+
[tool.poetry]
|
|
41
|
+
packages = [{include = "supersolid"}]
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
45
|
+
build-backend = "poetry.core.masonry.api"
|
|
46
|
+
|
|
47
|
+
[dependency-groups]
|
|
48
|
+
test = [
|
|
49
|
+
"pytest (>=9.1.1,<10.0.0)",
|
|
50
|
+
"pytest-cov (>=5.0.0,<7.0.0)"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
addopts = "--cov=supersolid --cov-report=term-missing"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|