power-openapi-models 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.
Files changed (31) hide show
  1. power_openapi_models-0.1.0/LICENSE +29 -0
  2. power_openapi_models-0.1.0/PKG-INFO +237 -0
  3. power_openapi_models-0.1.0/README.md +204 -0
  4. power_openapi_models-0.1.0/pyproject.toml +80 -0
  5. power_openapi_models-0.1.0/setup.cfg +4 -0
  6. power_openapi_models-0.1.0/src/power_openapi_models/__init__.py +52 -0
  7. power_openapi_models-0.1.0/src/power_openapi_models/_schema_version.txt +1 -0
  8. power_openapi_models-0.1.0/src/power_openapi_models/core/__init__.py +5 -0
  9. power_openapi_models-0.1.0/src/power_openapi_models/core/models.py +818 -0
  10. power_openapi_models-0.1.0/src/power_openapi_models/document.py +290 -0
  11. power_openapi_models-0.1.0/src/power_openapi_models/dynamics/__init__.py +5 -0
  12. power_openapi_models-0.1.0/src/power_openapi_models/dynamics/models.py +257 -0
  13. power_openapi_models-0.1.0/src/power_openapi_models/infrastructure_core/__init__.py +5 -0
  14. power_openapi_models-0.1.0/src/power_openapi_models/infrastructure_core/models.py +175 -0
  15. power_openapi_models-0.1.0/src/power_openapi_models/investments/__init__.py +5 -0
  16. power_openapi_models-0.1.0/src/power_openapi_models/investments/models.py +564 -0
  17. power_openapi_models-0.1.0/src/power_openapi_models/operations/__init__.py +5 -0
  18. power_openapi_models-0.1.0/src/power_openapi_models/operations/models.py +2958 -0
  19. power_openapi_models-0.1.0/src/power_openapi_models/py.typed +0 -0
  20. power_openapi_models-0.1.0/src/power_openapi_models/timeseries/__init__.py +5 -0
  21. power_openapi_models-0.1.0/src/power_openapi_models/timeseries/models.py +626 -0
  22. power_openapi_models-0.1.0/src/power_openapi_models.egg-info/PKG-INFO +237 -0
  23. power_openapi_models-0.1.0/src/power_openapi_models.egg-info/SOURCES.txt +29 -0
  24. power_openapi_models-0.1.0/src/power_openapi_models.egg-info/dependency_links.txt +1 -0
  25. power_openapi_models-0.1.0/src/power_openapi_models.egg-info/requires.txt +9 -0
  26. power_openapi_models-0.1.0/src/power_openapi_models.egg-info/top_level.txt +1 -0
  27. power_openapi_models-0.1.0/tests/test_document.py +219 -0
  28. power_openapi_models-0.1.0/tests/test_import.py +107 -0
  29. power_openapi_models-0.1.0/tests/test_public_api.py +129 -0
  30. power_openapi_models-0.1.0/tests/test_readme.py +39 -0
  31. power_openapi_models-0.1.0/tests/test_serde_fixture.py +165 -0
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026 Alliance for Energy Innovation, LLC and QXT Energy
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.4
2
+ Name: power-openapi-models
3
+ Version: 0.1.0
4
+ Summary: Typed Python models for the Sienna power system data format
5
+ Author: Sienna Platform
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/Sienna-Platform/power-openapi-models
8
+ Project-URL: Repository, https://github.com/Sienna-Platform/power-openapi-models
9
+ Project-URL: Issues, https://github.com/Sienna-Platform/power-openapi-models/issues
10
+ Project-URL: Changelog, https://github.com/Sienna-Platform/power-openapi-models/blob/main/CHANGELOG.md
11
+ Keywords: power-systems,energy,openapi,pydantic,sienna,time-series
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: pydantic>=2.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: ruff>=0.6; extra == "dev"
27
+ Requires-Dist: pytest>=8; extra == "dev"
28
+ Requires-Dist: pyright>=1.1.380; extra == "dev"
29
+ Requires-Dist: datamodel-code-generator; extra == "dev"
30
+ Requires-Dist: build; extra == "dev"
31
+ Requires-Dist: twine; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # power-openapi-models (Python)
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/power-openapi-models.svg)](https://pypi.org/project/power-openapi-models/)
37
+ [![Python](https://img.shields.io/pypi/pyversions/power-openapi-models.svg)](https://pypi.org/project/power-openapi-models/)
38
+ [![CI](https://github.com/Sienna-Platform/power-openapi-models/actions/workflows/test.yml/badge.svg)](https://github.com/Sienna-Platform/power-openapi-models/actions/workflows/test.yml)
39
+ [![License](https://img.shields.io/pypi/l/power-openapi-models.svg)](../LICENSE)
40
+
41
+ Typed Python models for the Sienna power system data format — every
42
+ component, association, and time series row as a validated pydantic v2
43
+ model.
44
+
45
+ > [!WARNING]
46
+ > **Pre-release.** Every version below `1.0` can change incompatibly in any
47
+ > release; no stability is promised until `1.0`. Under PEP 440, `0.1.0` is
48
+ > not itself a "pre-release" version, so `pip install power-openapi-models`
49
+ > installs it with no `--pre` flag and no warning. Pin an exact version.
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ pip install power-openapi-models
55
+ ```
56
+
57
+ ```bash
58
+ uv add power-openapi-models
59
+ ```
60
+
61
+ ## Quickstart
62
+
63
+ ```python
64
+ from power_openapi_models.core.models import ACBus, ACBusType
65
+
66
+ bus = ACBus(
67
+ id=1,
68
+ name="bus-1",
69
+ available=True,
70
+ number=1,
71
+ bustype=ACBusType.PV,
72
+ base_voltage=230.0,
73
+ )
74
+ print(bus.name, bus.bustype, bus.base_voltage)
75
+ print(bus.model_dump_json(exclude_none=True))
76
+ ```
77
+
78
+ ## The modules
79
+
80
+ | Module | Holds | Reach for it when |
81
+ |---|---|---|
82
+ | `infrastructure_core` | Units (`UnitSystem`), function data, shared value shapes (`MinMax`, `UpDown`, ...) | You need a domain-neutral building block used across every other module |
83
+ | `core` | Power enums, curves, costs, buses | You are working with shared power types or need `ACBus`/`DCBus` |
84
+ | `operations` | Topology, branches, injections, services, market | You are working with the grid itself |
85
+ | `investments` | Technologies, financials, requirements, regions | You are doing capacity expansion |
86
+ | `dynamics` | Dynamic generator and inverter components | You are doing transient stability |
87
+ | `timeseries` | The six time series association types | You are handling forecasts or profiles |
88
+ | `document` | `SystemDocument`, the hand-written envelope, plus `read_document`/`write_document` | You are loading or saving a whole serialized system |
89
+
90
+ Import a class from its module's `.models` submodule:
91
+ `from power_openapi_models.core.models import ACBus`.
92
+
93
+ ## Concepts worth knowing before you start
94
+
95
+ ### Unit systems
96
+
97
+ Many component fields carry a sibling `*_units` field (for example
98
+ `ThermalStandard.power_units`) that says how to read every other power-family
99
+ field on that same component. There is no document-level unit system: each
100
+ component blob is self-describing.
101
+
102
+ ```python
103
+ from power_openapi_models.infrastructure_core.models import UnitSystem
104
+
105
+ print(list(UnitSystem))
106
+ print(UnitSystem.NATURAL_UNITS.value)
107
+ ```
108
+
109
+ `NATURAL_UNITS` means values are in physical units — MW, MVAr, kV, ohm.
110
+ `COMPONENT_BASE` means per-unit against the component's own recorded
111
+ `base_power`. Getting this wrong is the most common source of
112
+ wrong-by-a-factor-of-100 bugs across the ecosystem.
113
+
114
+ ### Discriminated unions carry a `.root`
115
+
116
+ Several types are one of several shapes, chosen by a discriminator field.
117
+ They are pydantic `RootModel`s, and the concrete variant is reached through
118
+ `.root`.
119
+
120
+ ```python
121
+ from power_openapi_models.infrastructure_core.models import (
122
+ FunctionData,
123
+ LinearFunctionData,
124
+ )
125
+
126
+ parsed = FunctionData.model_validate(
127
+ {"function_type": "LINEAR", "proportional_term": 2.0, "constant_term": 5.0}
128
+ )
129
+ assert isinstance(parsed.root, LinearFunctionData)
130
+ print(parsed.root.proportional_term)
131
+ ```
132
+
133
+ > [!IMPORTANT]
134
+ > **This differs from the TypeScript package**, where the same types are zod
135
+ > unions and `parse` returns the variant directly, with no `.root`. Porting
136
+ > code between the two languages, this is the first thing that breaks.
137
+
138
+ ### Components reference each other by integer id
139
+
140
+ There are no object references on the wire. `ThermalStandard.bus`, for
141
+ example, names its bus by id, and resolving it is the reader's job.
142
+
143
+ ```python
144
+ from power_openapi_models.core.models import ACBus
145
+
146
+ buses = [
147
+ ACBus(id=1, name="a", available=True, number=1, base_voltage=230.0),
148
+ ACBus(id=2, name="b", available=True, number=2, base_voltage=230.0),
149
+ ]
150
+ by_id = {bus.id: bus for bus in buses}
151
+ print(by_id[2].name)
152
+ ```
153
+
154
+ ### The document envelope
155
+
156
+ A serialized system is one object: `components` keyed by type name, a flat
157
+ `supplemental_attributes` array, several association arrays, and
158
+ `time_series_storage_file` naming a sidecar. There is no document-level
159
+ `unit_system` or `base_power` — `SystemDocument` forbids both fields
160
+ outright, since every component already carries its own basis.
161
+
162
+ **Time series values never appear in the document.**
163
+ `time_series_associations` carries only the metadata rows; the values live
164
+ in the sidecar named by `time_series_storage_file`, and reading it is the
165
+ consumer's job.
166
+
167
+ ## Round-tripping
168
+
169
+ `read_document` followed by `write_document` reproduces the input byte for
170
+ byte. Fields the input never carried stay omitted rather than being written
171
+ back as explicit nulls, top-level keys are sorted, and the file ends with a
172
+ newline.
173
+
174
+ ## Worked example
175
+
176
+ ```python
177
+ from power_openapi_models.document import read_document
178
+
179
+ doc = read_document("../fixtures/case14_operations.NATURAL_UNITS.json")
180
+
181
+ buses = doc.components["ACBus"]
182
+ generators = doc.components["ThermalStandard"]
183
+ print(f"{len(buses)} buses, {len(generators)} thermal generators")
184
+
185
+ gen = generators[0]
186
+ limits = gen["active_power_limits"]
187
+ print(gen["name"], "active power limits (MW):", limits["min"], "-", limits["max"])
188
+ ```
189
+
190
+ ## Validation
191
+
192
+ Bad data raises `pydantic.ValidationError`, which names the field and the
193
+ rule:
194
+
195
+ ```python
196
+ from pydantic import ValidationError
197
+
198
+ from power_openapi_models.infrastructure_core.models import LinearFunctionData
199
+
200
+ try:
201
+ LinearFunctionData(function_type="NOT_A_TYPE", proportional_term=1.0, constant_term=0.0)
202
+ except ValidationError as exc:
203
+ print(exc.error_count(), "error(s)")
204
+ print(exc.errors()[0]["loc"], exc.errors()[0]["type"])
205
+ ```
206
+
207
+ ## Type checking
208
+
209
+ The package ships a PEP 561 `py.typed` marker, so mypy and pyright pick the
210
+ annotations up with no configuration.
211
+
212
+ ## Versioning and provenance
213
+
214
+ These models are generated. The schema release they came from is recorded
215
+ in the package:
216
+
217
+ ```python
218
+ import power_openapi_models
219
+
220
+ print(power_openapi_models.__version__)
221
+ print(power_openapi_models.__schema_version__)
222
+ ```
223
+
224
+ Quote `__schema_version__` in bug reports — it identifies the exact schema
225
+ release the models were built from.
226
+
227
+ ## Links
228
+
229
+ - [SiennaSchemas](https://github.com/Sienna-Platform/SiennaSchemas) — the schemas these models are generated from, and where schema bugs belong
230
+ - [@sienna-platform/power-openapi-models](../typescript/README.md) — the TypeScript package generated from the same schemas, kept in lockstep by a CI equivalence gate
231
+ - [PowerOpenAPIModels.jl](https://github.com/Sienna-Platform/PowerOpenAPIModels) — the Julia packages generated from the same schemas
232
+ - [CONTRIBUTING.md](../CONTRIBUTING.md) — regenerating, and why you must not edit the models by hand
233
+ - [CHANGELOG.md](../CHANGELOG.md)
234
+
235
+ ## License
236
+
237
+ BSD 3-Clause. See [LICENSE](../LICENSE).
@@ -0,0 +1,204 @@
1
+ # power-openapi-models (Python)
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/power-openapi-models.svg)](https://pypi.org/project/power-openapi-models/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/power-openapi-models.svg)](https://pypi.org/project/power-openapi-models/)
5
+ [![CI](https://github.com/Sienna-Platform/power-openapi-models/actions/workflows/test.yml/badge.svg)](https://github.com/Sienna-Platform/power-openapi-models/actions/workflows/test.yml)
6
+ [![License](https://img.shields.io/pypi/l/power-openapi-models.svg)](../LICENSE)
7
+
8
+ Typed Python models for the Sienna power system data format — every
9
+ component, association, and time series row as a validated pydantic v2
10
+ model.
11
+
12
+ > [!WARNING]
13
+ > **Pre-release.** Every version below `1.0` can change incompatibly in any
14
+ > release; no stability is promised until `1.0`. Under PEP 440, `0.1.0` is
15
+ > not itself a "pre-release" version, so `pip install power-openapi-models`
16
+ > installs it with no `--pre` flag and no warning. Pin an exact version.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install power-openapi-models
22
+ ```
23
+
24
+ ```bash
25
+ uv add power-openapi-models
26
+ ```
27
+
28
+ ## Quickstart
29
+
30
+ ```python
31
+ from power_openapi_models.core.models import ACBus, ACBusType
32
+
33
+ bus = ACBus(
34
+ id=1,
35
+ name="bus-1",
36
+ available=True,
37
+ number=1,
38
+ bustype=ACBusType.PV,
39
+ base_voltage=230.0,
40
+ )
41
+ print(bus.name, bus.bustype, bus.base_voltage)
42
+ print(bus.model_dump_json(exclude_none=True))
43
+ ```
44
+
45
+ ## The modules
46
+
47
+ | Module | Holds | Reach for it when |
48
+ |---|---|---|
49
+ | `infrastructure_core` | Units (`UnitSystem`), function data, shared value shapes (`MinMax`, `UpDown`, ...) | You need a domain-neutral building block used across every other module |
50
+ | `core` | Power enums, curves, costs, buses | You are working with shared power types or need `ACBus`/`DCBus` |
51
+ | `operations` | Topology, branches, injections, services, market | You are working with the grid itself |
52
+ | `investments` | Technologies, financials, requirements, regions | You are doing capacity expansion |
53
+ | `dynamics` | Dynamic generator and inverter components | You are doing transient stability |
54
+ | `timeseries` | The six time series association types | You are handling forecasts or profiles |
55
+ | `document` | `SystemDocument`, the hand-written envelope, plus `read_document`/`write_document` | You are loading or saving a whole serialized system |
56
+
57
+ Import a class from its module's `.models` submodule:
58
+ `from power_openapi_models.core.models import ACBus`.
59
+
60
+ ## Concepts worth knowing before you start
61
+
62
+ ### Unit systems
63
+
64
+ Many component fields carry a sibling `*_units` field (for example
65
+ `ThermalStandard.power_units`) that says how to read every other power-family
66
+ field on that same component. There is no document-level unit system: each
67
+ component blob is self-describing.
68
+
69
+ ```python
70
+ from power_openapi_models.infrastructure_core.models import UnitSystem
71
+
72
+ print(list(UnitSystem))
73
+ print(UnitSystem.NATURAL_UNITS.value)
74
+ ```
75
+
76
+ `NATURAL_UNITS` means values are in physical units — MW, MVAr, kV, ohm.
77
+ `COMPONENT_BASE` means per-unit against the component's own recorded
78
+ `base_power`. Getting this wrong is the most common source of
79
+ wrong-by-a-factor-of-100 bugs across the ecosystem.
80
+
81
+ ### Discriminated unions carry a `.root`
82
+
83
+ Several types are one of several shapes, chosen by a discriminator field.
84
+ They are pydantic `RootModel`s, and the concrete variant is reached through
85
+ `.root`.
86
+
87
+ ```python
88
+ from power_openapi_models.infrastructure_core.models import (
89
+ FunctionData,
90
+ LinearFunctionData,
91
+ )
92
+
93
+ parsed = FunctionData.model_validate(
94
+ {"function_type": "LINEAR", "proportional_term": 2.0, "constant_term": 5.0}
95
+ )
96
+ assert isinstance(parsed.root, LinearFunctionData)
97
+ print(parsed.root.proportional_term)
98
+ ```
99
+
100
+ > [!IMPORTANT]
101
+ > **This differs from the TypeScript package**, where the same types are zod
102
+ > unions and `parse` returns the variant directly, with no `.root`. Porting
103
+ > code between the two languages, this is the first thing that breaks.
104
+
105
+ ### Components reference each other by integer id
106
+
107
+ There are no object references on the wire. `ThermalStandard.bus`, for
108
+ example, names its bus by id, and resolving it is the reader's job.
109
+
110
+ ```python
111
+ from power_openapi_models.core.models import ACBus
112
+
113
+ buses = [
114
+ ACBus(id=1, name="a", available=True, number=1, base_voltage=230.0),
115
+ ACBus(id=2, name="b", available=True, number=2, base_voltage=230.0),
116
+ ]
117
+ by_id = {bus.id: bus for bus in buses}
118
+ print(by_id[2].name)
119
+ ```
120
+
121
+ ### The document envelope
122
+
123
+ A serialized system is one object: `components` keyed by type name, a flat
124
+ `supplemental_attributes` array, several association arrays, and
125
+ `time_series_storage_file` naming a sidecar. There is no document-level
126
+ `unit_system` or `base_power` — `SystemDocument` forbids both fields
127
+ outright, since every component already carries its own basis.
128
+
129
+ **Time series values never appear in the document.**
130
+ `time_series_associations` carries only the metadata rows; the values live
131
+ in the sidecar named by `time_series_storage_file`, and reading it is the
132
+ consumer's job.
133
+
134
+ ## Round-tripping
135
+
136
+ `read_document` followed by `write_document` reproduces the input byte for
137
+ byte. Fields the input never carried stay omitted rather than being written
138
+ back as explicit nulls, top-level keys are sorted, and the file ends with a
139
+ newline.
140
+
141
+ ## Worked example
142
+
143
+ ```python
144
+ from power_openapi_models.document import read_document
145
+
146
+ doc = read_document("../fixtures/case14_operations.NATURAL_UNITS.json")
147
+
148
+ buses = doc.components["ACBus"]
149
+ generators = doc.components["ThermalStandard"]
150
+ print(f"{len(buses)} buses, {len(generators)} thermal generators")
151
+
152
+ gen = generators[0]
153
+ limits = gen["active_power_limits"]
154
+ print(gen["name"], "active power limits (MW):", limits["min"], "-", limits["max"])
155
+ ```
156
+
157
+ ## Validation
158
+
159
+ Bad data raises `pydantic.ValidationError`, which names the field and the
160
+ rule:
161
+
162
+ ```python
163
+ from pydantic import ValidationError
164
+
165
+ from power_openapi_models.infrastructure_core.models import LinearFunctionData
166
+
167
+ try:
168
+ LinearFunctionData(function_type="NOT_A_TYPE", proportional_term=1.0, constant_term=0.0)
169
+ except ValidationError as exc:
170
+ print(exc.error_count(), "error(s)")
171
+ print(exc.errors()[0]["loc"], exc.errors()[0]["type"])
172
+ ```
173
+
174
+ ## Type checking
175
+
176
+ The package ships a PEP 561 `py.typed` marker, so mypy and pyright pick the
177
+ annotations up with no configuration.
178
+
179
+ ## Versioning and provenance
180
+
181
+ These models are generated. The schema release they came from is recorded
182
+ in the package:
183
+
184
+ ```python
185
+ import power_openapi_models
186
+
187
+ print(power_openapi_models.__version__)
188
+ print(power_openapi_models.__schema_version__)
189
+ ```
190
+
191
+ Quote `__schema_version__` in bug reports — it identifies the exact schema
192
+ release the models were built from.
193
+
194
+ ## Links
195
+
196
+ - [SiennaSchemas](https://github.com/Sienna-Platform/SiennaSchemas) — the schemas these models are generated from, and where schema bugs belong
197
+ - [@sienna-platform/power-openapi-models](../typescript/README.md) — the TypeScript package generated from the same schemas, kept in lockstep by a CI equivalence gate
198
+ - [PowerOpenAPIModels.jl](https://github.com/Sienna-Platform/PowerOpenAPIModels) — the Julia packages generated from the same schemas
199
+ - [CONTRIBUTING.md](../CONTRIBUTING.md) — regenerating, and why you must not edit the models by hand
200
+ - [CHANGELOG.md](../CHANGELOG.md)
201
+
202
+ ## License
203
+
204
+ BSD 3-Clause. See [LICENSE](../LICENSE).
@@ -0,0 +1,80 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "power-openapi-models"
7
+ version = "0.1.0"
8
+ description = "Typed Python models for the Sienna power system data format"
9
+ readme = "README.md"
10
+ license = "BSD-3-Clause"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [{ name = "Sienna Platform" }]
14
+ keywords = [
15
+ "power-systems",
16
+ "energy",
17
+ "openapi",
18
+ "pydantic",
19
+ "sienna",
20
+ "time-series",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 3 - Alpha",
24
+ "Intended Audience :: Science/Research",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Programming Language :: Python :: 3.14",
31
+ "Typing :: Typed",
32
+ ]
33
+ dependencies = [
34
+ "pydantic>=2.0",
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/Sienna-Platform/power-openapi-models"
39
+ Repository = "https://github.com/Sienna-Platform/power-openapi-models"
40
+ Issues = "https://github.com/Sienna-Platform/power-openapi-models/issues"
41
+ Changelog = "https://github.com/Sienna-Platform/power-openapi-models/blob/main/CHANGELOG.md"
42
+
43
+ [project.optional-dependencies]
44
+ dev = [
45
+ "ruff>=0.6",
46
+ "pytest>=8",
47
+ "pyright>=1.1.380",
48
+ "datamodel-code-generator",
49
+ "build",
50
+ "twine",
51
+ ]
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["src"]
55
+
56
+ [tool.setuptools.package-data]
57
+ power_openapi_models = ["py.typed", "_schema_version.txt"]
58
+
59
+ [tool.ruff]
60
+ line-length = 100
61
+ # models.py files are generated; their formatting is the generator's business.
62
+ # SiennaSchemas is a sibling checkout (local dev) or a CI-only checkout for the
63
+ # document tests (see .github/workflows/test.yml); its own scripts are out of scope.
64
+ extend-exclude = ["src/power_openapi_models/*/models.py", "SiennaSchemas"]
65
+
66
+ [tool.ruff.lint]
67
+ select = ["E", "F", "I", "UP", "B", "W"]
68
+ # E741 (ambiguous variable name): the generated models are field-for-field with
69
+ # SiennaSchemas' power-system quantities, which use standard electrical-engineering
70
+ # single-letter names (e.g. `l` for inductance) -- not something to rename away from.
71
+ ignore = ["E741"]
72
+
73
+ [tool.pytest.ini_options]
74
+ testpaths = ["tests"]
75
+ addopts = "-ra --strict-markers"
76
+
77
+ [tool.pyright]
78
+ include = ["src"]
79
+ extraPaths = ["src"]
80
+ pythonVersion = "3.10"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,52 @@
1
+ """Typed Python models for the Sienna power system data format.
2
+
3
+ Generated from SiennaSchemas. See `__schema_version__` for the schema release
4
+ these models were built from.
5
+ """
6
+
7
+ from importlib.metadata import PackageNotFoundError
8
+ from importlib.metadata import version as _version
9
+ from pathlib import Path
10
+
11
+ from power_openapi_models import (
12
+ core,
13
+ document,
14
+ dynamics,
15
+ infrastructure_core,
16
+ investments,
17
+ operations,
18
+ timeseries,
19
+ )
20
+
21
+ try:
22
+ __version__ = _version("power-openapi-models")
23
+ except PackageNotFoundError: # running from a source tree, not installed
24
+ __version__ = "0.0.0.dev0"
25
+
26
+
27
+ def _read_schema_version() -> str:
28
+ """The SiennaSchemas release these models were generated from.
29
+
30
+ Shipped as package data so it is answerable at runtime -- the first
31
+ question worth asking about a generated model is which schema produced it.
32
+ """
33
+ marker = Path(__file__).parent / "_schema_version.txt"
34
+ try:
35
+ return marker.read_text().strip()
36
+ except OSError:
37
+ return "unknown"
38
+
39
+
40
+ __schema_version__ = _read_schema_version()
41
+
42
+ __all__ = [
43
+ "core",
44
+ "document",
45
+ "dynamics",
46
+ "infrastructure_core",
47
+ "investments",
48
+ "operations",
49
+ "timeseries",
50
+ "__version__",
51
+ "__schema_version__",
52
+ ]
@@ -0,0 +1,5 @@
1
+ """Auto-generated stubs for the core domain."""
2
+
3
+ from power_openapi_models.core import models
4
+
5
+ __all__ = ["models"]