dynapydantic 0.1.0__tar.gz → 0.1.1__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.
Files changed (52) hide show
  1. dynapydantic-0.1.1/.github/workflows/deploy-docs.yml +42 -0
  2. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/.gitignore +3 -0
  3. dynapydantic-0.1.1/PKG-INFO +139 -0
  4. dynapydantic-0.1.1/README.md +129 -0
  5. dynapydantic-0.1.1/docs/README.md +1 -0
  6. dynapydantic-0.1.1/docs/reference.md +3 -0
  7. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/class_index.html +2 -2
  8. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/function_index.html +12 -12
  9. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/index.html +2 -2
  10. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/status.json +1 -1
  11. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/z_f3e6dac33013b94d___init___py.html +2 -2
  12. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/z_f3e6dac33013b94d_exceptions_py.html +2 -2
  13. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/z_f3e6dac33013b94d_subclass_tracking_model_py.html +108 -91
  14. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/z_f3e6dac33013b94d_tracking_group_py.html +2 -2
  15. dynapydantic-0.1.1/mkdocs.yml +53 -0
  16. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/pyproject.toml +6 -1
  17. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/src/dynapydantic/subclass_tracking_model.py +18 -1
  18. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/uv.lock +514 -1
  19. dynapydantic-0.1.0/PKG-INFO +0 -21
  20. dynapydantic-0.1.0/README.md +0 -11
  21. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/.github/workflows/ci.yml +0 -0
  22. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/.github/workflows/pre-commit.yml +0 -0
  23. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/.pre-commit-config.yaml +0 -0
  24. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/.python-version +0 -0
  25. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/LICENSE +0 -0
  26. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/.gitignore +0 -0
  27. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/coverage_html_cb_6fb7b396.js +0 -0
  28. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/favicon_32_cb_58284776.png +0 -0
  29. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/keybd_closed_cb_ce680311.png +0 -0
  30. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/htmlcov/style_cb_81f8c14c.css +0 -0
  31. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/src/dynapydantic/__init__.py +0 -0
  32. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/src/dynapydantic/exceptions.py +0 -0
  33. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/src/dynapydantic/py.typed +0 -0
  34. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/src/dynapydantic/tracking_group.py +0 -0
  35. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/__init__.py +0 -0
  36. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/animal-plugins/animal_plugins/__init__.py +0 -0
  37. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/animal-plugins/pyproject.toml +0 -0
  38. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/__init__.py +0 -0
  39. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/__main__.py +0 -0
  40. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/animal.py +0 -0
  41. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/cat.py +0 -0
  42. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/circle.py +0 -0
  43. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/cli.py +0 -0
  44. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/base_package/shape.py +0 -0
  45. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/base-package/pyproject.toml +0 -0
  46. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/shape-plugins/pyproject.toml +0 -0
  47. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/shape-plugins/shape_plugins/__init__.py +0 -0
  48. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/shape-plugins/shape_plugins/plugin_classes.py +0 -0
  49. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/example/shape-plugins/shape_plugins/registration.py +0 -0
  50. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/test_plugins.py +0 -0
  51. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/test_subclass_tracking_model.py +0 -0
  52. {dynapydantic-0.1.0 → dynapydantic-0.1.1}/tests/test_tracking_group.py +0 -0
@@ -0,0 +1,42 @@
1
+ name: Deploy versioned docs to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*' # deploy when a version tag is pushed
7
+ branches:
8
+ - main # deploy dev version on main
9
+
10
+ permissions:
11
+ contents: write
12
+
13
+ jobs:
14
+ deploy:
15
+ runs-on: ubuntu-latest
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0 # mike needs access to full git history
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v6
23
+ - name: Install the project
24
+ run: uv sync --locked --all-extras --dev
25
+ - name: Get version info
26
+ id: vars
27
+ run: |
28
+ VERSION=${GITHUB_REF#refs/tags/}
29
+ echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
30
+ if: startsWith(github.ref, 'refs/tags/')
31
+ - name: Set Git identity
32
+ run: |
33
+ git config user.name "github-actions[bot]"
34
+ git config user.email "github-actions[bot]@users.noreply.github.com"
35
+ - name: Deploy tagged release
36
+ if: startsWith(github.ref, 'refs/tags/')
37
+ run: |
38
+ uv run mike deploy ${{ steps.vars.outputs.version }} --update-aliases latest --push
39
+ uv run mike set-default latest --push
40
+ - name: Deploy dev version from main
41
+ if: github.ref == 'refs/heads/main'
42
+ run: uv run mike deploy dev --push --update-aliases
@@ -15,3 +15,6 @@ wheels/
15
15
 
16
16
  # OS files
17
17
  .DS_Store
18
+
19
+ # MKDocs
20
+ site
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: dynapydantic
3
+ Version: 0.1.1
4
+ Summary: Dyanmic pydantic models
5
+ Author-email: Philip Salvaggio <salvaggio.philip@gmail.com>
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: pydantic>=2.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # dynapydantic
12
+
13
+ [![CI](https://github.com/psalvaggio/dynapydantic/actions/workflows/ci.yml/badge.svg)](https://github.com/psalvaggio/dynapydantic/actions/workflows/ci.yml)
14
+ [![Pre-commit](https://github.com/psalvaggio/dynapydantic/actions/workflows/pre-commit.yml/badge.svg)](https://github.com/psalvaggio/dynapydantic/actions/workflows/pre-commit.yml)
15
+ [![Docs](https://img.shields.io/badge/docs-Docs-blue?style=flat-square&logo=github&logoColor=white&link=https://psalvaggio.github.io/dynapydantic/dev/)](https://psalvaggio.github.io/dynapydantic/dev/)
16
+
17
+
18
+ `dynapydantic` is an extension to the [pydantic](https://pydantic.dev) Python
19
+ package that allow for dynamic tracking of `pydantic.BaseModel` subclasses.
20
+
21
+ Installation
22
+ ==
23
+ This project can be installed via PyPI:
24
+ ```
25
+ pip install dynapydantic
26
+ ```
27
+
28
+ Usage
29
+ ==
30
+
31
+ `TrackingGroup`
32
+ --
33
+ The core entity in this library is the `dynapydantic.TrackingGroup`:
34
+ ```python
35
+ import typing as ty
36
+
37
+ import dynapydantic
38
+ import pydantic
39
+
40
+ mygroup = dynapydantic.TrackingGroup(
41
+ name="mygroup",
42
+ discriminator_field="name"
43
+ )
44
+
45
+ @mygroup.register("A")
46
+ class A(pydantic.BaseModel):
47
+ """A class to be tracked, will be tracked as "A"."""
48
+ a: int
49
+
50
+ @mygroup.register()
51
+ class B(pydantic.BaseModel):
52
+ """Another class, will be tracked as "B"."""
53
+ name: ty.Literal["B"] = "B"
54
+ a: int
55
+
56
+ class Model(pydantic.BaseModel):
57
+ """A model that can have A or B"""
58
+ field: mygroup.union() # call after all subclasses have been registered
59
+
60
+ print(Model(field={"name": "A", "a": 4})) # field=A(a=4, name='A')
61
+ print(Model(field={"name": "B", "a": 5})) # field=B(name='B', a=5)
62
+ ```
63
+
64
+ The `union()` method produces a [discriminated union](https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions)
65
+ of all registered `pydantic.BaseModel` subclasses. It also accepts an
66
+ `annotated=False` keyword argument to produce a plain `typing.Union` for use in
67
+ type annotations. This union is based on a discriminator field, which was
68
+ configured by the `discriminator_field` argument to `TrackingGroup`. The field
69
+ can be created by hand, as was shown with `B`, or `dynapydantic` will inject it
70
+ for you, as was shown with `A`.
71
+
72
+ `TrackingGroup` has a few opt-in features to make it more powerful and easier to use:
73
+ 1. `discriminator_value_generator`: This parameter is a optional callback
74
+ function that is called with each class that gets registered and produces a
75
+ default value for the discriminator field. This allows the user to call
76
+ `register()` without a value for the discriminator. The most common value to
77
+ pass here would be `lambda cls: cls.__name__`, to use the name of the class as
78
+ the discriminator value.
79
+ 2. `plugin_entry_point`: This parameter indicates to `dynapydantic` that there
80
+ might be models to be discovered in other packages. Packages are discovered by
81
+ the Python entrypoint mechanism. See the `tests/example` directory for an
82
+ example of how this works.
83
+
84
+ `SubclassTrackingModel`
85
+ --
86
+ The most common use case of this pattern is to automatically register subclasses
87
+ of a given `pydantic.BaseModel`. This is supported via the use of
88
+ `dynapydantic.SubclassTrackingModel`. For example:
89
+ ```python
90
+ import typing as ty
91
+
92
+ import dynapydantic
93
+ import pydantic
94
+
95
+ class Base(
96
+ dynapydantic.SubclassTrackingModel,
97
+ discriminator_field="name",
98
+ discriminator_value_generator=lambda cls: cls.__name__,
99
+ ):
100
+ """Base model, will track its subclasses"""
101
+
102
+ # The TrackingGroup can be specified here like model_config, or passed in
103
+ # kwargs of the class declaration, just like how model_config works with
104
+ # pydantic.BaseModel. If you do it like this, you have to give the tracking
105
+ # group a name
106
+ # tracking_config: ty.ClassVar[dynapydantic.TrackingGroup] = dynapydantic.TrackingGroup(
107
+ # name="BaseSubclasses",
108
+ # discriminator_field="name",
109
+ # discriminator_value_generator=lambda cls: cls.__name__,
110
+ # )
111
+
112
+
113
+ class Intermediate(Base, exclude_from_union=True):
114
+ """Subclasses can opt out of being tracked"""
115
+
116
+ class Derived1(Intermediate):
117
+ """Non-direct descendants are registered"""
118
+ a: int
119
+
120
+ class Derived2(Intermediate):
121
+ """You can override the value generator if desired"""
122
+ name: ty.Literal["Custom"] = "Custom"
123
+ a: int
124
+
125
+ print(Base.registered_subclasses())
126
+ # {'Derived1': <class '__main__.Derived1'>, 'Custom': <class '__main__.Derived2'>}
127
+
128
+ # if plugin_entry_point was specificed, load plugin packages
129
+ # Base.load_plugins()
130
+
131
+ class Model(pydantic.BaseModel):
132
+ """A model that can have any registered Base subclass"""
133
+ field: Base.union() # call after all subclasses have been registered
134
+
135
+ print(Model(field={"name": "Derived1", "a": 4}))
136
+ # field=Derived1(a=4, name='Derived1')
137
+ print(Model(field={"name": "Custom", "a": 5}))
138
+ # field=Derived2(name='Custom', a=5)
139
+ ```
@@ -0,0 +1,129 @@
1
+ # dynapydantic
2
+
3
+ [![CI](https://github.com/psalvaggio/dynapydantic/actions/workflows/ci.yml/badge.svg)](https://github.com/psalvaggio/dynapydantic/actions/workflows/ci.yml)
4
+ [![Pre-commit](https://github.com/psalvaggio/dynapydantic/actions/workflows/pre-commit.yml/badge.svg)](https://github.com/psalvaggio/dynapydantic/actions/workflows/pre-commit.yml)
5
+ [![Docs](https://img.shields.io/badge/docs-Docs-blue?style=flat-square&logo=github&logoColor=white&link=https://psalvaggio.github.io/dynapydantic/dev/)](https://psalvaggio.github.io/dynapydantic/dev/)
6
+
7
+
8
+ `dynapydantic` is an extension to the [pydantic](https://pydantic.dev) Python
9
+ package that allow for dynamic tracking of `pydantic.BaseModel` subclasses.
10
+
11
+ Installation
12
+ ==
13
+ This project can be installed via PyPI:
14
+ ```
15
+ pip install dynapydantic
16
+ ```
17
+
18
+ Usage
19
+ ==
20
+
21
+ `TrackingGroup`
22
+ --
23
+ The core entity in this library is the `dynapydantic.TrackingGroup`:
24
+ ```python
25
+ import typing as ty
26
+
27
+ import dynapydantic
28
+ import pydantic
29
+
30
+ mygroup = dynapydantic.TrackingGroup(
31
+ name="mygroup",
32
+ discriminator_field="name"
33
+ )
34
+
35
+ @mygroup.register("A")
36
+ class A(pydantic.BaseModel):
37
+ """A class to be tracked, will be tracked as "A"."""
38
+ a: int
39
+
40
+ @mygroup.register()
41
+ class B(pydantic.BaseModel):
42
+ """Another class, will be tracked as "B"."""
43
+ name: ty.Literal["B"] = "B"
44
+ a: int
45
+
46
+ class Model(pydantic.BaseModel):
47
+ """A model that can have A or B"""
48
+ field: mygroup.union() # call after all subclasses have been registered
49
+
50
+ print(Model(field={"name": "A", "a": 4})) # field=A(a=4, name='A')
51
+ print(Model(field={"name": "B", "a": 5})) # field=B(name='B', a=5)
52
+ ```
53
+
54
+ The `union()` method produces a [discriminated union](https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions)
55
+ of all registered `pydantic.BaseModel` subclasses. It also accepts an
56
+ `annotated=False` keyword argument to produce a plain `typing.Union` for use in
57
+ type annotations. This union is based on a discriminator field, which was
58
+ configured by the `discriminator_field` argument to `TrackingGroup`. The field
59
+ can be created by hand, as was shown with `B`, or `dynapydantic` will inject it
60
+ for you, as was shown with `A`.
61
+
62
+ `TrackingGroup` has a few opt-in features to make it more powerful and easier to use:
63
+ 1. `discriminator_value_generator`: This parameter is a optional callback
64
+ function that is called with each class that gets registered and produces a
65
+ default value for the discriminator field. This allows the user to call
66
+ `register()` without a value for the discriminator. The most common value to
67
+ pass here would be `lambda cls: cls.__name__`, to use the name of the class as
68
+ the discriminator value.
69
+ 2. `plugin_entry_point`: This parameter indicates to `dynapydantic` that there
70
+ might be models to be discovered in other packages. Packages are discovered by
71
+ the Python entrypoint mechanism. See the `tests/example` directory for an
72
+ example of how this works.
73
+
74
+ `SubclassTrackingModel`
75
+ --
76
+ The most common use case of this pattern is to automatically register subclasses
77
+ of a given `pydantic.BaseModel`. This is supported via the use of
78
+ `dynapydantic.SubclassTrackingModel`. For example:
79
+ ```python
80
+ import typing as ty
81
+
82
+ import dynapydantic
83
+ import pydantic
84
+
85
+ class Base(
86
+ dynapydantic.SubclassTrackingModel,
87
+ discriminator_field="name",
88
+ discriminator_value_generator=lambda cls: cls.__name__,
89
+ ):
90
+ """Base model, will track its subclasses"""
91
+
92
+ # The TrackingGroup can be specified here like model_config, or passed in
93
+ # kwargs of the class declaration, just like how model_config works with
94
+ # pydantic.BaseModel. If you do it like this, you have to give the tracking
95
+ # group a name
96
+ # tracking_config: ty.ClassVar[dynapydantic.TrackingGroup] = dynapydantic.TrackingGroup(
97
+ # name="BaseSubclasses",
98
+ # discriminator_field="name",
99
+ # discriminator_value_generator=lambda cls: cls.__name__,
100
+ # )
101
+
102
+
103
+ class Intermediate(Base, exclude_from_union=True):
104
+ """Subclasses can opt out of being tracked"""
105
+
106
+ class Derived1(Intermediate):
107
+ """Non-direct descendants are registered"""
108
+ a: int
109
+
110
+ class Derived2(Intermediate):
111
+ """You can override the value generator if desired"""
112
+ name: ty.Literal["Custom"] = "Custom"
113
+ a: int
114
+
115
+ print(Base.registered_subclasses())
116
+ # {'Derived1': <class '__main__.Derived1'>, 'Custom': <class '__main__.Derived2'>}
117
+
118
+ # if plugin_entry_point was specificed, load plugin packages
119
+ # Base.load_plugins()
120
+
121
+ class Model(pydantic.BaseModel):
122
+ """A model that can have any registered Base subclass"""
123
+ field: Base.union() # call after all subclasses have been registered
124
+
125
+ print(Model(field={"name": "Derived1", "a": 4}))
126
+ # field=Derived1(a=4, name='Derived1')
127
+ print(Model(field={"name": "Custom", "a": 5}))
128
+ # field=Derived2(name='Custom', a=5)
129
+ ```
@@ -0,0 +1 @@
1
+ ../README.md
@@ -0,0 +1,3 @@
1
+ # API Reference
2
+
3
+ ::: dynapydantic
@@ -57,7 +57,7 @@
57
57
  </h2>
58
58
  <p class="text">
59
59
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
60
- created at 2025-07-11 18:47 +0000
60
+ created at 2025-07-11 20:37 +0000
61
61
  </p>
62
62
  </div>
63
63
  </header>
@@ -198,7 +198,7 @@
198
198
  <div class="content">
199
199
  <p>
200
200
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
201
- created at 2025-07-11 18:47 +0000
201
+ created at 2025-07-11 20:37 +0000
202
202
  </p>
203
203
  </div>
204
204
  <aside class="hidden">
@@ -57,7 +57,7 @@
57
57
  </h2>
58
58
  <p class="text">
59
59
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
60
- created at 2025-07-11 18:47 +0000
60
+ created at 2025-07-11 20:37 +0000
61
61
  </p>
62
62
  </div>
63
63
  </header>
@@ -107,8 +107,8 @@
107
107
  <td class="right" data-ratio="1 1">100%</td>
108
108
  </tr>
109
109
  <tr class="region">
110
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t31">src/dynapydantic/subclass_tracking_model.py</a></td>
111
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t31"><data value='init_subclass__'>SubclassTrackingModel.__init_subclass__</data></a></td>
110
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t48">src/dynapydantic/subclass_tracking_model.py</a></td>
111
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t48"><data value='init_subclass__'>SubclassTrackingModel.__init_subclass__</data></a></td>
112
112
  <td>1</td>
113
113
  <td>0</td>
114
114
  <td>0</td>
@@ -117,8 +117,8 @@
117
117
  <td class="right" data-ratio="1 1">100%</td>
118
118
  </tr>
119
119
  <tr class="region">
120
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t45">src/dynapydantic/subclass_tracking_model.py</a></td>
121
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t45"><data value='pydantic_init_subclass__'>SubclassTrackingModel.__pydantic_init_subclass__</data></a></td>
120
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t62">src/dynapydantic/subclass_tracking_model.py</a></td>
121
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t62"><data value='pydantic_init_subclass__'>SubclassTrackingModel.__pydantic_init_subclass__</data></a></td>
122
122
  <td>23</td>
123
123
  <td>0</td>
124
124
  <td>0</td>
@@ -127,8 +127,8 @@
127
127
  <td class="right" data-ratio="33 33">100%</td>
128
128
  </tr>
129
129
  <tr class="region">
130
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t84">src/dynapydantic/subclass_tracking_model.py</a></td>
131
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t84"><data value='load_plugins'>SubclassTrackingModel.__pydantic_init_subclass__._load_plugins</data></a></td>
130
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t101">src/dynapydantic/subclass_tracking_model.py</a></td>
131
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t101"><data value='load_plugins'>SubclassTrackingModel.__pydantic_init_subclass__._load_plugins</data></a></td>
132
132
  <td>1</td>
133
133
  <td>0</td>
134
134
  <td>0</td>
@@ -137,8 +137,8 @@
137
137
  <td class="right" data-ratio="1 1">100%</td>
138
138
  </tr>
139
139
  <tr class="region">
140
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t90">src/dynapydantic/subclass_tracking_model.py</a></td>
141
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t90"><data value='union'>SubclassTrackingModel.__pydantic_init_subclass__._union</data></a></td>
140
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t107">src/dynapydantic/subclass_tracking_model.py</a></td>
141
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t107"><data value='union'>SubclassTrackingModel.__pydantic_init_subclass__._union</data></a></td>
142
142
  <td>1</td>
143
143
  <td>0</td>
144
144
  <td>0</td>
@@ -147,8 +147,8 @@
147
147
  <td class="right" data-ratio="1 1">100%</td>
148
148
  </tr>
149
149
  <tr class="region">
150
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t104">src/dynapydantic/subclass_tracking_model.py</a></td>
151
- <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t104"><data value='subclasses'>SubclassTrackingModel.__pydantic_init_subclass__._subclasses</data></a></td>
150
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t121">src/dynapydantic/subclass_tracking_model.py</a></td>
151
+ <td class="name left"><a href="z_f3e6dac33013b94d_subclass_tracking_model_py.html#t121"><data value='subclasses'>SubclassTrackingModel.__pydantic_init_subclass__._subclasses</data></a></td>
152
152
  <td>1</td>
153
153
  <td>0</td>
154
154
  <td>0</td>
@@ -268,7 +268,7 @@
268
268
  <div class="content">
269
269
  <p>
270
270
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
271
- created at 2025-07-11 18:47 +0000
271
+ created at 2025-07-11 20:37 +0000
272
272
  </p>
273
273
  </div>
274
274
  <aside class="hidden">
@@ -56,7 +56,7 @@
56
56
  </h2>
57
57
  <p class="text">
58
58
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
59
- created at 2025-07-11 18:47 +0000
59
+ created at 2025-07-11 20:37 +0000
60
60
  </p>
61
61
  </div>
62
62
  </header>
@@ -131,7 +131,7 @@
131
131
  <div class="content">
132
132
  <p>
133
133
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
134
- created at 2025-07-11 18:47 +0000
134
+ created at 2025-07-11 20:37 +0000
135
135
  </p>
136
136
  </div>
137
137
  <aside class="hidden">
@@ -1 +1 @@
1
- {"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.9.2","globals":"43d70f8747b0bfec6e4cc124de1e27d8","files":{"z_f3e6dac33013b94d___init___py":{"hash":"2edda4a7815bc2158270461b713badd0","index":{"url":"z_f3e6dac33013b94d___init___py.html","file":"src/dynapydantic/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_f3e6dac33013b94d_exceptions_py":{"hash":"62421bef97bb275000b3d3675b40facb","index":{"url":"z_f3e6dac33013b94d_exceptions_py.html","file":"src/dynapydantic/exceptions.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_f3e6dac33013b94d_subclass_tracking_model_py":{"hash":"fbc2a17b4597afbba298a2b6e2fe8ad1","index":{"url":"z_f3e6dac33013b94d_subclass_tracking_model_py.html","file":"src/dynapydantic/subclass_tracking_model.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":37,"n_excluded":0,"n_missing":0,"n_branches":10,"n_partial_branches":0,"n_missing_branches":0}}},"z_f3e6dac33013b94d_tracking_group_py":{"hash":"56ab34c033f327c1175957f887b296bd","index":{"url":"z_f3e6dac33013b94d_tracking_group_py.html","file":"src/dynapydantic/tracking_group.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":61,"n_excluded":0,"n_missing":0,"n_branches":22,"n_partial_branches":0,"n_missing_branches":0}}}}}
1
+ {"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.9.2","globals":"43d70f8747b0bfec6e4cc124de1e27d8","files":{"z_f3e6dac33013b94d___init___py":{"hash":"2edda4a7815bc2158270461b713badd0","index":{"url":"z_f3e6dac33013b94d___init___py.html","file":"src/dynapydantic/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_f3e6dac33013b94d_exceptions_py":{"hash":"62421bef97bb275000b3d3675b40facb","index":{"url":"z_f3e6dac33013b94d_exceptions_py.html","file":"src/dynapydantic/exceptions.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":4,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_f3e6dac33013b94d_subclass_tracking_model_py":{"hash":"cb373169351e74066fc86370aeb90161","index":{"url":"z_f3e6dac33013b94d_subclass_tracking_model_py.html","file":"src/dynapydantic/subclass_tracking_model.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":37,"n_excluded":0,"n_missing":0,"n_branches":10,"n_partial_branches":0,"n_missing_branches":0}}},"z_f3e6dac33013b94d_tracking_group_py":{"hash":"56ab34c033f327c1175957f887b296bd","index":{"url":"z_f3e6dac33013b94d_tracking_group_py.html","file":"src/dynapydantic/tracking_group.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":61,"n_excluded":0,"n_missing":0,"n_branches":22,"n_partial_branches":0,"n_missing_branches":0}}}}}
@@ -67,7 +67,7 @@
67
67
  <a id="nextFileLink" class="nav" href="z_f3e6dac33013b94d_exceptions_py.html">&#xbb; next</a>
68
68
  &nbsp; &nbsp; &nbsp;
69
69
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
70
- created at 2025-07-11 18:47 +0000
70
+ created at 2025-07-11 20:37 +0000
71
71
  </p>
72
72
  <aside class="hidden">
73
73
  <button type="button" class="button_next_chunk" data-shortcut="j"></button>
@@ -110,7 +110,7 @@
110
110
  <a class="nav" href="z_f3e6dac33013b94d_exceptions_py.html">&#xbb; next</a>
111
111
  &nbsp; &nbsp; &nbsp;
112
112
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
113
- created at 2025-07-11 18:47 +0000
113
+ created at 2025-07-11 20:37 +0000
114
114
  </p>
115
115
  </div>
116
116
  </footer>
@@ -67,7 +67,7 @@
67
67
  <a id="nextFileLink" class="nav" href="z_f3e6dac33013b94d_subclass_tracking_model_py.html">&#xbb; next</a>
68
68
  &nbsp; &nbsp; &nbsp;
69
69
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
70
- created at 2025-07-11 18:47 +0000
70
+ created at 2025-07-11 20:37 +0000
71
71
  </p>
72
72
  <aside class="hidden">
73
73
  <button type="button" class="button_next_chunk" data-shortcut="j"></button>
@@ -108,7 +108,7 @@
108
108
  <a class="nav" href="z_f3e6dac33013b94d_subclass_tracking_model_py.html">&#xbb; next</a>
109
109
  &nbsp; &nbsp; &nbsp;
110
110
  <a class="nav" href="https://coverage.readthedocs.io/en/7.9.2">coverage.py v7.9.2</a>,
111
- created at 2025-07-11 18:47 +0000
111
+ created at 2025-07-11 20:37 +0000
112
112
  </p>
113
113
  </div>
114
114
  </footer>