openepd 6.13.2__py3-none-any.whl → 7.0.0__py3-none-any.whl
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.
- openepd/__init__.py +4 -4
- openepd/__version__.py +1 -1
- openepd/api/average_dataset/generic_estimate_sync_api.py +11 -10
- openepd/api/average_dataset/industry_epd_sync_api.py +9 -8
- openepd/api/base_sync_client.py +53 -9
- openepd/api/category/sync_api.py +1 -1
- openepd/api/dto/base.py +4 -4
- openepd/api/dto/common.py +24 -16
- openepd/api/dto/meta.py +15 -11
- openepd/api/dto/mf.py +9 -8
- openepd/api/epd/dto.py +43 -33
- openepd/api/epd/sync_api.py +9 -9
- openepd/api/pcr/sync_api.py +2 -2
- openepd/bundle/model.py +11 -10
- openepd/bundle/reader.py +12 -5
- openepd/bundle/writer.py +17 -6
- openepd/model/base.py +60 -43
- openepd/model/category.py +13 -10
- openepd/model/common.py +100 -55
- openepd/model/declaration.py +93 -64
- openepd/model/epd.py +51 -43
- openepd/model/generic_estimate.py +28 -13
- openepd/model/industry_epd.py +15 -9
- openepd/model/lcia.py +132 -113
- openepd/model/org.py +54 -33
- openepd/model/pcr.py +38 -32
- openepd/model/specs/asphalt.py +31 -22
- openepd/model/specs/base.py +11 -9
- openepd/model/specs/concrete.py +60 -39
- openepd/model/specs/range/aggregates.py +9 -9
- openepd/model/specs/range/aluminium.py +7 -7
- openepd/model/specs/range/asphalt.py +22 -19
- openepd/model/specs/range/cladding.py +16 -16
- openepd/model/specs/range/cmu.py +10 -9
- openepd/model/specs/range/concrete.py +36 -27
- openepd/model/specs/range/conveying_equipment.py +16 -15
- openepd/model/specs/range/electrical.py +24 -22
- openepd/model/specs/range/finishes.py +109 -104
- openepd/model/specs/range/fire_and_smoke_protection.py +7 -7
- openepd/model/specs/range/furnishings.py +16 -12
- openepd/model/specs/range/manufacturing_inputs.py +16 -16
- openepd/model/specs/range/masonry.py +16 -16
- openepd/model/specs/range/mechanical.py +47 -47
- openepd/model/specs/range/mechanical_insulation.py +7 -7
- openepd/model/specs/range/network_infrastructure.py +54 -46
- openepd/model/specs/range/openings.py +36 -31
- openepd/model/specs/range/plumbing.py +15 -13
- openepd/model/specs/range/precast_concrete.py +20 -16
- openepd/model/specs/range/sheathing.py +18 -18
- openepd/model/specs/range/steel.py +25 -25
- openepd/model/specs/range/thermal_moisture_protection.py +20 -20
- openepd/model/specs/range/utility_piping.py +9 -9
- openepd/model/specs/range/wood.py +19 -19
- openepd/model/specs/range/wood_joists.py +8 -8
- openepd/model/specs/singular/__init__.py +9 -5
- openepd/model/specs/singular/aggregates.py +22 -15
- openepd/model/specs/singular/aluminium.py +20 -5
- openepd/model/specs/singular/asphalt.py +44 -20
- openepd/model/specs/singular/cladding.py +38 -23
- openepd/model/specs/singular/cmu.py +26 -11
- openepd/model/specs/singular/common.py +3 -2
- openepd/model/specs/singular/concrete.py +85 -48
- openepd/model/specs/singular/conveying_equipment.py +30 -17
- openepd/model/specs/singular/deprecated/__init__.py +3 -2
- openepd/model/specs/singular/deprecated/concrete.py +68 -33
- openepd/model/specs/singular/deprecated/steel.py +28 -15
- openepd/model/specs/singular/electrical.py +69 -41
- openepd/model/specs/singular/finishes.py +250 -140
- openepd/model/specs/singular/fire_and_smoke_protection.py +9 -6
- openepd/model/specs/singular/furnishings.py +16 -14
- openepd/model/specs/singular/manufacturing_inputs.py +23 -14
- openepd/model/specs/singular/masonry.py +66 -21
- openepd/model/specs/singular/mechanical.py +48 -47
- openepd/model/specs/singular/mechanical_insulation.py +7 -6
- openepd/model/specs/singular/mixins/conduit_mixin.py +13 -10
- openepd/model/specs/singular/network_infrastructure.py +111 -52
- openepd/model/specs/singular/openings.py +127 -95
- openepd/model/specs/singular/plumbing.py +15 -12
- openepd/model/specs/singular/precast_concrete.py +68 -54
- openepd/model/specs/singular/sheathing.py +47 -27
- openepd/model/specs/singular/steel.py +69 -45
- openepd/model/specs/singular/thermal_moisture_protection.py +36 -20
- openepd/model/specs/singular/utility_piping.py +11 -8
- openepd/model/specs/singular/wood.py +48 -24
- openepd/model/specs/singular/wood_joists.py +19 -6
- openepd/model/standard.py +15 -8
- openepd/model/validation/common.py +9 -3
- openepd/model/validation/numbers.py +0 -13
- openepd/model/validation/quantity.py +53 -25
- openepd/model/versioning.py +9 -6
- openepd/patch_pydantic.py +0 -93
- {openepd-6.13.2.dist-info → openepd-7.0.0.dist-info}/METADATA +1 -1
- openepd-7.0.0.dist-info/RECORD +142 -0
- openepd/compat/__init__.py +0 -15
- openepd/compat/compat_functional_validators.py +0 -25
- openepd/compat/pydantic.py +0 -30
- openepd-6.13.2.dist-info/RECORD +0 -145
- {openepd-6.13.2.dist-info → openepd-7.0.0.dist-info}/LICENSE +0 -0
- {openepd-6.13.2.dist-info → openepd-7.0.0.dist-info}/WHEEL +0 -0
@@ -13,7 +13,8 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
|
16
|
+
import pydantic
|
17
|
+
|
17
18
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
|
18
19
|
from openepd.model.specs.enums import (
|
19
20
|
FoamType,
|
@@ -23,7 +24,6 @@ from openepd.model.specs.enums import (
|
|
23
24
|
RoofCoverBoardsFacing,
|
24
25
|
RoofCoverBoardsMaterial,
|
25
26
|
)
|
26
|
-
from openepd.model.validation.numbers import RatioFloat
|
27
27
|
from openepd.model.validation.quantity import LengthMmStr, PressureMPaStr
|
28
28
|
|
29
29
|
|
@@ -95,7 +95,7 @@ class BoardInsulationV1(BaseOpenEpdHierarchicalSpec):
|
|
95
95
|
_EXT_VERSION = "1.0"
|
96
96
|
|
97
97
|
# Own fields:
|
98
|
-
compressive_strength: PressureMPaStr | None =
|
98
|
+
compressive_strength: PressureMPaStr | None = pydantic.Field(default=None, description="", examples=["1 MPa"])
|
99
99
|
|
100
100
|
|
101
101
|
class FoamedInPlaceV1(BaseOpenEpdHierarchicalSpec):
|
@@ -104,7 +104,7 @@ class FoamedInPlaceV1(BaseOpenEpdHierarchicalSpec):
|
|
104
104
|
_EXT_VERSION = "1.0"
|
105
105
|
|
106
106
|
# Own fields:
|
107
|
-
foam_type: FoamType | None =
|
107
|
+
foam_type: FoamType | None = pydantic.Field(default=None, description="", examples=["Open-Cell"])
|
108
108
|
|
109
109
|
|
110
110
|
class SprayedInsulationV1(BaseOpenEpdHierarchicalSpec):
|
@@ -134,14 +134,30 @@ class MembraneRoofingV1(BaseOpenEpdHierarchicalSpec):
|
|
134
134
|
_EXT_VERSION = "1.0"
|
135
135
|
|
136
136
|
# Own fields:
|
137
|
-
thickness: LengthMmStr | None =
|
138
|
-
sri: float | None =
|
139
|
-
total_recycled_content:
|
140
|
-
post_consumer_recycled_content:
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
137
|
+
thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["10 mm"])
|
138
|
+
sri: float | None = pydantic.Field(default=None, description="", examples=[2.3])
|
139
|
+
total_recycled_content: float | None = pydantic.Field(default=None, description="", examples=[0.5], ge=0, le=1)
|
140
|
+
post_consumer_recycled_content: float | None = pydantic.Field(
|
141
|
+
default=None, description="", examples=[0.5], ge=0, le=1
|
142
|
+
)
|
143
|
+
reinforcement: MembraneRoofingReinforcement | None = pydantic.Field(
|
144
|
+
default=None, description="", examples=["Polyester"]
|
145
|
+
)
|
146
|
+
felt_backing: bool | None = pydantic.Field(
|
147
|
+
default=None,
|
148
|
+
description="",
|
149
|
+
examples=[True],
|
150
|
+
)
|
151
|
+
nsf347: bool | None = pydantic.Field(
|
152
|
+
default=None,
|
153
|
+
description="",
|
154
|
+
examples=[True],
|
155
|
+
)
|
156
|
+
vantage_vinyl: bool | None = pydantic.Field(
|
157
|
+
default=None,
|
158
|
+
description="",
|
159
|
+
examples=[True],
|
160
|
+
)
|
145
161
|
|
146
162
|
# Nested specs:
|
147
163
|
BituminousRoofing: BituminousRoofingV1 | None = None
|
@@ -159,12 +175,12 @@ class InsulationV1(BaseOpenEpdHierarchicalSpec):
|
|
159
175
|
_EXT_VERSION = "1.0"
|
160
176
|
|
161
177
|
# Own fields:
|
162
|
-
r_value: float | None =
|
163
|
-
material: InsulatingMaterial | None =
|
164
|
-
intended_application: list[InsulationIntendedApplication] | None =
|
165
|
-
default=None, description="",
|
178
|
+
r_value: float | None = pydantic.Field(default=None, description="", examples=[2.3])
|
179
|
+
material: InsulatingMaterial | None = pydantic.Field(default=None, description="", examples=["Mineral Wool"])
|
180
|
+
intended_application: list[InsulationIntendedApplication] | None = pydantic.Field(
|
181
|
+
default=None, description="", examples=[["Wall & General"]]
|
166
182
|
)
|
167
|
-
thickness_per_declared_unit: LengthMmStr | None =
|
183
|
+
thickness_per_declared_unit: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["10 mm"])
|
168
184
|
|
169
185
|
# Nested specs:
|
170
186
|
BlanketInsulation: BlanketInsulationV1 | None = None
|
@@ -207,9 +223,9 @@ class RoofCoverBoardsV1(BaseOpenEpdHierarchicalSpec):
|
|
207
223
|
_EXT_VERSION = "1.0"
|
208
224
|
|
209
225
|
# Own fields:
|
210
|
-
material: RoofCoverBoardsMaterial | None =
|
211
|
-
facing: list[RoofCoverBoardsFacing] | None =
|
212
|
-
thickness: LengthMmStr | None =
|
226
|
+
material: RoofCoverBoardsMaterial | None = pydantic.Field(default=None, description="", examples=["Gypsum Fiber"])
|
227
|
+
facing: list[RoofCoverBoardsFacing] | None = pydantic.Field(default=None, description="", examples=[["Paper"]])
|
228
|
+
thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["1 m"])
|
213
229
|
|
214
230
|
|
215
231
|
class SteepSlopeRoofingV1(BaseOpenEpdHierarchicalSpec):
|
@@ -13,7 +13,8 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
|
16
|
+
import pydantic
|
17
|
+
|
17
18
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
|
18
19
|
from openepd.model.specs.enums import BuriedPipingType, PipingAnsiSchedule, UtilityPipingMaterial
|
19
20
|
from openepd.model.validation.quantity import LengthMmStr, MassPerLengthStr
|
@@ -36,8 +37,8 @@ class BuriedPipingV1(BaseOpenEpdHierarchicalSpec):
|
|
36
37
|
_EXT_VERSION = "1.0"
|
37
38
|
|
38
39
|
# Own fields:
|
39
|
-
buried_piping_type: list[BuriedPipingType] | None =
|
40
|
-
default=None, description="",
|
40
|
+
buried_piping_type: list[BuriedPipingType] | None = pydantic.Field(
|
41
|
+
default=None, description="", examples=[["Water Utilities"]]
|
41
42
|
)
|
42
43
|
|
43
44
|
|
@@ -52,11 +53,13 @@ class UtilityPipingV1(BaseOpenEpdHierarchicalSpec):
|
|
52
53
|
_EXT_VERSION = "1.0"
|
53
54
|
|
54
55
|
# Own fields:
|
55
|
-
thickness: LengthMmStr | None =
|
56
|
-
piping_diameter: LengthMmStr | None =
|
57
|
-
mass_per_unit_length: MassPerLengthStr | None =
|
58
|
-
piping_ansi_schedule: PipingAnsiSchedule | None =
|
59
|
-
utility_piping_material: UtilityPipingMaterial | None =
|
56
|
+
thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["6 m"])
|
57
|
+
piping_diameter: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["200 mm"])
|
58
|
+
mass_per_unit_length: MassPerLengthStr | None = pydantic.Field(default=None, description="", examples=["1 kg / m"])
|
59
|
+
piping_ansi_schedule: PipingAnsiSchedule | None = pydantic.Field(default=None, description="", examples=["5"])
|
60
|
+
utility_piping_material: UtilityPipingMaterial | None = pydantic.Field(
|
61
|
+
default=None, description="", examples=["PVC"]
|
62
|
+
)
|
60
63
|
|
61
64
|
# Nested specs:
|
62
65
|
BuildingHeatingPiping: BuildingHeatingPipingV1 | None = None
|
@@ -15,7 +15,8 @@
|
|
15
15
|
#
|
16
16
|
from typing import Annotated
|
17
17
|
|
18
|
-
|
18
|
+
import pydantic
|
19
|
+
|
19
20
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec, CodegenSpec
|
20
21
|
from openepd.model.specs.enums import (
|
21
22
|
AllFabrication,
|
@@ -27,7 +28,6 @@ from openepd.model.specs.enums import (
|
|
27
28
|
SheathingPanelsFabrication,
|
28
29
|
)
|
29
30
|
from openepd.model.specs.singular.common import HasForestPracticesCertifiers
|
30
|
-
from openepd.model.validation.numbers import RatioFloat
|
31
31
|
from openepd.model.validation.quantity import LengthMmStr
|
32
32
|
|
33
33
|
|
@@ -72,8 +72,10 @@ class CompositeLumberV1(BaseOpenEpdHierarchicalSpec):
|
|
72
72
|
|
73
73
|
_EXT_VERSION = "1.0"
|
74
74
|
|
75
|
-
fabrication: CompositeLumberFabrication | None =
|
76
|
-
timber_species: EngineeredTimberSpecies | None =
|
75
|
+
fabrication: CompositeLumberFabrication | None = pydantic.Field(default=None, description="", examples=["LVL"])
|
76
|
+
timber_species: EngineeredTimberSpecies | None = pydantic.Field(
|
77
|
+
default=None, description="", examples=["Alaska Cedar"]
|
78
|
+
)
|
77
79
|
|
78
80
|
|
79
81
|
class DimensionLumberV1(BaseOpenEpdHierarchicalSpec):
|
@@ -82,7 +84,7 @@ class DimensionLumberV1(BaseOpenEpdHierarchicalSpec):
|
|
82
84
|
_EXT_VERSION = "1.0"
|
83
85
|
|
84
86
|
# Nested specs:
|
85
|
-
timber_species: SawnTimberSpecies | None =
|
87
|
+
timber_species: SawnTimberSpecies | None = pydantic.Field(default=None, description="", examples=["Alaska Cedar"])
|
86
88
|
WoodDecking: WoodDeckingV1 | None = None
|
87
89
|
WoodFraming: WoodFramingV1 | None = None
|
88
90
|
|
@@ -103,8 +105,10 @@ class MassTimberV1(BaseOpenEpdHierarchicalSpec):
|
|
103
105
|
|
104
106
|
_EXT_VERSION = "1.0"
|
105
107
|
|
106
|
-
fabrication: MassTimberFabrication | None =
|
107
|
-
timber_species: EngineeredTimberSpecies | None =
|
108
|
+
fabrication: MassTimberFabrication | None = pydantic.Field(default=None, description="", examples=["CLT"])
|
109
|
+
timber_species: EngineeredTimberSpecies | None = pydantic.Field(
|
110
|
+
default=None, description="", examples=["Alaska Cedar"]
|
111
|
+
)
|
108
112
|
|
109
113
|
|
110
114
|
class NonStructuralWoodV1(BaseOpenEpdHierarchicalSpec):
|
@@ -134,9 +138,11 @@ class SheathingPanelsV1(BaseOpenEpdHierarchicalSpec):
|
|
134
138
|
_EXT_VERSION = "1.0"
|
135
139
|
|
136
140
|
# Own fields:
|
137
|
-
fabrication: SheathingPanelsFabrication | None =
|
138
|
-
wood_board_thickness: LengthMmStr | None =
|
139
|
-
timber_species: EngineeredTimberSpecies | None =
|
141
|
+
fabrication: SheathingPanelsFabrication | None = pydantic.Field(default=None, description="", examples=["Plywood"])
|
142
|
+
wood_board_thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["10 mm"])
|
143
|
+
timber_species: EngineeredTimberSpecies | None = pydantic.Field(
|
144
|
+
default=None, description="", examples=["Alaska Cedar"]
|
145
|
+
)
|
140
146
|
|
141
147
|
|
142
148
|
class UnfinishedWoodV1(BaseOpenEpdHierarchicalSpec):
|
@@ -151,25 +157,43 @@ class WoodV1(BaseOpenEpdHierarchicalSpec, HasForestPracticesCertifiers):
|
|
151
157
|
_EXT_VERSION = "1.0"
|
152
158
|
|
153
159
|
# Own fields:
|
154
|
-
timber_species: AllTimberSpecies | None =
|
155
|
-
default=None, description="Timber species",
|
160
|
+
timber_species: AllTimberSpecies | None = pydantic.Field(
|
161
|
+
default=None, description="Timber species", examples=["Alaska Cedar"]
|
162
|
+
)
|
163
|
+
fabrication: AllFabrication | None = pydantic.Field(
|
164
|
+
default=None, description="Timber fabrication", examples=["LVL"]
|
165
|
+
)
|
166
|
+
weather_exposed: bool | None = pydantic.Field(
|
167
|
+
default=None,
|
168
|
+
description="Weather exposed",
|
169
|
+
examples=[True],
|
170
|
+
)
|
171
|
+
fire_retardant: bool | None = pydantic.Field(
|
172
|
+
default=None,
|
173
|
+
description="Fire retardant",
|
174
|
+
examples=[True],
|
175
|
+
)
|
176
|
+
decay_resistant: bool | None = pydantic.Field(
|
177
|
+
default=None,
|
178
|
+
description="Decay resistant",
|
179
|
+
examples=[True],
|
156
180
|
)
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
181
|
+
fsc_certified: Annotated[float | None, CodegenSpec(override_type=float)] = pydantic.Field(
|
182
|
+
default=None,
|
183
|
+
description="Forest Stewardship Council certified proportion",
|
184
|
+
examples=[0.3],
|
185
|
+
ge=0,
|
186
|
+
le=1,
|
163
187
|
)
|
164
|
-
fsc_certified_z: Annotated[float | None, CodegenSpec(override_type=float)] =
|
165
|
-
default=None, description="",
|
188
|
+
fsc_certified_z: Annotated[float | None, CodegenSpec(override_type=float)] = pydantic.Field(
|
189
|
+
default=None, description="", examples=[0.7]
|
166
190
|
)
|
167
191
|
|
168
|
-
recycled_content: Annotated[
|
169
|
-
default=None, description="Recycled content",
|
192
|
+
recycled_content: Annotated[float | None, CodegenSpec(override_type=float)] = pydantic.Field(
|
193
|
+
default=None, description="Recycled content", examples=[0.3], ge=0, le=1
|
170
194
|
)
|
171
|
-
recycled_content_z: Annotated[float | None, CodegenSpec(override_type=float)] =
|
172
|
-
default=None, description="",
|
195
|
+
recycled_content_z: Annotated[float | None, CodegenSpec(override_type=float)] = pydantic.Field(
|
196
|
+
default=None, description="", examples=[0.7]
|
173
197
|
)
|
174
198
|
|
175
199
|
# Nested specs:
|
@@ -13,7 +13,8 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
|
16
|
+
import pydantic
|
17
|
+
|
17
18
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
|
18
19
|
from openepd.model.specs.enums import AllFabrication, AllTimberSpecies
|
19
20
|
from openepd.model.specs.singular.common import HasForestPracticesCertifiers
|
@@ -30,8 +31,20 @@ class WoodJoistsV1(BaseOpenEpdHierarchicalSpec, HasForestPracticesCertifiers):
|
|
30
31
|
_EXT_VERSION = "1.0"
|
31
32
|
|
32
33
|
# Own fields:
|
33
|
-
timber_species: AllTimberSpecies | None =
|
34
|
-
fabrication: AllFabrication | None =
|
35
|
-
weather_exposed: bool | None =
|
36
|
-
|
37
|
-
|
34
|
+
timber_species: AllTimberSpecies | None = pydantic.Field(default=None, description="", examples=["Alaska Cedar"])
|
35
|
+
fabrication: AllFabrication | None = pydantic.Field(default=None, description="", examples=["LVL"])
|
36
|
+
weather_exposed: bool | None = pydantic.Field(
|
37
|
+
default=None,
|
38
|
+
description="",
|
39
|
+
examples=[True],
|
40
|
+
)
|
41
|
+
fire_retardant: bool | None = pydantic.Field(
|
42
|
+
default=None,
|
43
|
+
description="",
|
44
|
+
examples=[True],
|
45
|
+
)
|
46
|
+
decay_resistant: bool | None = pydantic.Field(
|
47
|
+
default=None,
|
48
|
+
description="",
|
49
|
+
examples=[True],
|
50
|
+
)
|
openepd/model/standard.py
CHANGED
@@ -13,7 +13,8 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
|
16
|
+
import pydantic
|
17
|
+
|
17
18
|
from openepd.model.base import BaseOpenEpdSchema
|
18
19
|
from openepd.model.org import OrgRef
|
19
20
|
from openepd.model.validation.common import ReferenceStr
|
@@ -22,19 +23,25 @@ from openepd.model.validation.common import ReferenceStr
|
|
22
23
|
class StandardRef(BaseOpenEpdSchema):
|
23
24
|
"""Reference version (short) of Standard."""
|
24
25
|
|
25
|
-
ref: ReferenceStr | None =
|
26
|
+
ref: ReferenceStr | None = pydantic.Field(
|
26
27
|
default=None,
|
27
|
-
|
28
|
+
examples=["https://openepd.buildingtransparency.org/api/standards/EN15804"],
|
28
29
|
description="Reference to this Standard's JSON object",
|
29
30
|
)
|
30
|
-
short_name: str | None =
|
31
|
+
short_name: str | None = pydantic.Field(
|
32
|
+
description="Short-form of name of standard. Must be unique. Case-insensitive"
|
33
|
+
)
|
31
34
|
|
32
35
|
|
33
36
|
class Standard(StandardRef):
|
34
37
|
"""A standard, such as EN 15804, ISO 14044, ISO 14024:2018, etc."""
|
35
38
|
|
36
|
-
name: str | None =
|
37
|
-
|
38
|
-
|
39
|
+
name: str | None = pydantic.Field(
|
40
|
+
description="Full document name. Must be unique. Case-insensitive",
|
41
|
+
default=None,
|
42
|
+
)
|
43
|
+
link: pydantic.AnyUrl | None = pydantic.Field(
|
44
|
+
description="Link to the exact standard (including version) referred to",
|
45
|
+
default=None,
|
39
46
|
)
|
40
|
-
issuer: OrgRef | None =
|
47
|
+
issuer: OrgRef | None = pydantic.Field(description="Org that issued this standard", default=None)
|
@@ -15,7 +15,8 @@
|
|
15
15
|
#
|
16
16
|
from typing import Annotated, Any, Callable, Type, TypeAlias
|
17
17
|
|
18
|
-
|
18
|
+
import pydantic
|
19
|
+
|
19
20
|
from openepd.model.versioning import Version
|
20
21
|
|
21
22
|
|
@@ -33,7 +34,9 @@ def validate_version_format(v: str) -> str:
|
|
33
34
|
return v
|
34
35
|
|
35
36
|
|
36
|
-
def validate_version_compatibility(
|
37
|
+
def validate_version_compatibility(
|
38
|
+
class_version_attribute_name: str,
|
39
|
+
) -> Callable[[Type, str], str]:
|
37
40
|
"""Ensure that the object which is passed for parsing and validation is compatible with the class."""
|
38
41
|
|
39
42
|
# we need closure to pass property name, since actual class will only be available in runtime
|
@@ -51,5 +54,8 @@ def validate_version_compatibility(class_version_attribute_name: str) -> Callabl
|
|
51
54
|
|
52
55
|
ReferenceStr: TypeAlias = Annotated[
|
53
56
|
str,
|
54
|
-
|
57
|
+
pydantic.Field(
|
58
|
+
description="Reference to another object",
|
59
|
+
examples=["https://buildingtransparency.org/ec3/epds/1u7zsed8"],
|
60
|
+
),
|
55
61
|
]
|
@@ -13,16 +13,3 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
|
17
|
-
|
18
|
-
# todo when move to pydantic 2, these should change to Annotated[float, ...]
|
19
|
-
class RatioFloat(float):
|
20
|
-
"""Float representing a ratio (0-1)."""
|
21
|
-
|
22
|
-
pass
|
23
|
-
|
24
|
-
|
25
|
-
class PositiveInt(int):
|
26
|
-
"""Greater than zero integer."""
|
27
|
-
|
28
|
-
pass
|
@@ -16,7 +16,10 @@
|
|
16
16
|
from abc import ABC, abstractmethod
|
17
17
|
from typing import TYPE_CHECKING, Any, Callable, ClassVar
|
18
18
|
|
19
|
-
|
19
|
+
import pydantic
|
20
|
+
from pydantic import ConfigDict
|
21
|
+
import pydantic_core
|
22
|
+
|
20
23
|
from openepd.model.base import BaseOpenEpdSchema
|
21
24
|
from openepd.model.common import Amount, OpenEPDUnit, RangeAmount
|
22
25
|
|
@@ -113,7 +116,9 @@ def validate_unit_factory(dimensionality: OpenEPDUnit | str) -> "QuantityValidat
|
|
113
116
|
return validator
|
114
117
|
|
115
118
|
|
116
|
-
def validate_quantity_unit_factory(
|
119
|
+
def validate_quantity_unit_factory(
|
120
|
+
dimensionality: OpenEPDUnit | str,
|
121
|
+
) -> "QuantityValidatorType":
|
117
122
|
"""Create validator for quantity field to check unit matching."""
|
118
123
|
|
119
124
|
def validator(cls: type | None, value: str) -> str:
|
@@ -162,18 +167,33 @@ class QuantityStr(str):
|
|
162
167
|
unit: ClassVar[str]
|
163
168
|
|
164
169
|
@classmethod
|
165
|
-
def
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
yield validate_quantity_ge_factory(f"0 {cls.unit}")
|
170
|
+
def _validate(cls, value: str) -> str:
|
171
|
+
value = validate_quantity_unit_factory(cls.unit)(cls, value)
|
172
|
+
value = validate_quantity_ge_factory(f"0 {cls.unit}")(cls, value)
|
173
|
+
return value
|
170
174
|
|
171
175
|
@classmethod
|
172
|
-
def
|
173
|
-
|
174
|
-
|
176
|
+
def __get_pydantic_core_schema__(
|
177
|
+
cls, source: type[Any], handler: pydantic.GetCoreSchemaHandler
|
178
|
+
) -> pydantic_core.core_schema.CoreSchema:
|
179
|
+
return pydantic_core.core_schema.no_info_after_validator_function(
|
180
|
+
cls._validate,
|
181
|
+
pydantic_core.core_schema.str_schema(),
|
182
|
+
serialization=pydantic_core.core_schema.plain_serializer_function_ser_schema(
|
183
|
+
lambda x: x,
|
184
|
+
info_arg=False,
|
185
|
+
return_schema=pydantic_core.core_schema.str_schema(),
|
186
|
+
),
|
175
187
|
)
|
176
188
|
|
189
|
+
@classmethod
|
190
|
+
def __get_pydantic_json_schema__(cls, core_schema, handler):
|
191
|
+
schema = handler(core_schema)
|
192
|
+
schema.update(
|
193
|
+
examples=[f"1 {cls.unit}"],
|
194
|
+
)
|
195
|
+
return schema
|
196
|
+
|
177
197
|
|
178
198
|
class PressureMPaStr(QuantityStr):
|
179
199
|
"""Pressure quantity type."""
|
@@ -205,10 +225,12 @@ class LengthMmStr(QuantityStr):
|
|
205
225
|
unit = OpenEPDUnit.m
|
206
226
|
|
207
227
|
@classmethod
|
208
|
-
def
|
209
|
-
|
210
|
-
|
228
|
+
def __get_pydantic_json_schema__(cls, core_schema, handler):
|
229
|
+
schema = handler(core_schema)
|
230
|
+
schema.update(
|
231
|
+
examples=["6 mm"],
|
211
232
|
)
|
233
|
+
return schema
|
212
234
|
|
213
235
|
|
214
236
|
class LengthInchStr(QuantityStr):
|
@@ -217,10 +239,12 @@ class LengthInchStr(QuantityStr):
|
|
217
239
|
unit = "inch"
|
218
240
|
|
219
241
|
@classmethod
|
220
|
-
def
|
221
|
-
|
222
|
-
|
242
|
+
def __get_pydantic_json_schema__(cls, core_schema, handler):
|
243
|
+
schema = handler(core_schema)
|
244
|
+
schema.update(
|
245
|
+
examples=["2.5 inch"],
|
223
246
|
)
|
247
|
+
return schema
|
224
248
|
|
225
249
|
|
226
250
|
class TemperatureCStr(QuantityStr):
|
@@ -356,26 +380,30 @@ class WithDimensionalityMixin(BaseOpenEpdSchema):
|
|
356
380
|
|
357
381
|
# Unit for dimensionality to validate against, for example "kg"
|
358
382
|
|
359
|
-
@
|
383
|
+
@pydantic.model_validator(mode="before")
|
360
384
|
def check_dimensionality_matches(cls, values: dict[str, Any]) -> dict[str, Any]:
|
361
385
|
"""Check that this amount conforms to the same dimensionality as dimensionality_unit."""
|
362
386
|
if not cls.dimensionality_unit:
|
363
387
|
return values
|
364
388
|
|
365
|
-
validate_unit_factory(cls.dimensionality_unit)(BaseOpenEpdSchema, values.get("unit")) # type:ignore
|
389
|
+
validate_unit_factory(cls.dimensionality_unit)(BaseOpenEpdSchema, values.get("unit")) # type: ignore[arg-type]
|
366
390
|
return values
|
367
391
|
|
368
392
|
|
369
393
|
class AmountRangeWithDimensionality(RangeAmount, WithDimensionalityMixin):
|
370
394
|
"""Mass amount, range."""
|
371
395
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
396
|
+
model_config = ConfigDict(
|
397
|
+
json_schema_extra=lambda schema, model: schema.update(
|
398
|
+
{
|
399
|
+
"example": {
|
400
|
+
"min": 1.2,
|
401
|
+
"max": 3.4,
|
402
|
+
"unit": str(model.dimensionality_unit) or None,
|
403
|
+
}
|
404
|
+
}
|
405
|
+
)
|
406
|
+
)
|
379
407
|
|
380
408
|
|
381
409
|
class WithMassKgMixin(WithDimensionalityMixin):
|
openepd/model/versioning.py
CHANGED
@@ -17,10 +17,10 @@ from abc import ABC
|
|
17
17
|
from enum import ReprEnum
|
18
18
|
from typing import ClassVar, NamedTuple
|
19
19
|
|
20
|
-
|
20
|
+
import pydantic
|
21
21
|
|
22
22
|
|
23
|
-
class WithExtVersionMixin(ABC,
|
23
|
+
class WithExtVersionMixin(ABC, pydantic.BaseModel):
|
24
24
|
"""Mixin for extensions supporting versions: recommended way."""
|
25
25
|
|
26
26
|
_EXT_VERSION: ClassVar[str]
|
@@ -30,10 +30,10 @@ class WithExtVersionMixin(ABC, pyd.BaseModel):
|
|
30
30
|
"""Set the default value for the ext_version field from _EXT_VERSION class var."""
|
31
31
|
super().__init_subclass__()
|
32
32
|
if hasattr(cls, "_EXT_VERSION"):
|
33
|
-
cls.
|
33
|
+
cls.model_fields["ext_version"].default = cls._EXT_VERSION
|
34
34
|
|
35
35
|
# Note: default is set programmatically in __init_subclass__
|
36
|
-
ext_version: str | None =
|
36
|
+
ext_version: str | None = pydantic.Field(description="Extension version", examples=["3.22"], default=None)
|
37
37
|
|
38
38
|
|
39
39
|
class Version(NamedTuple):
|
@@ -43,7 +43,7 @@ class Version(NamedTuple):
|
|
43
43
|
minor: int
|
44
44
|
|
45
45
|
@staticmethod
|
46
|
-
def parse_version(version: str) -> "Version":
|
46
|
+
def parse_version(version: str | None) -> "Version":
|
47
47
|
"""Parse the version of extension or the format.
|
48
48
|
|
49
49
|
Version is expected to be major.minor
|
@@ -51,7 +51,10 @@ class Version(NamedTuple):
|
|
51
51
|
:param version: The extension version.
|
52
52
|
:return: A tuple of major and minor version numbers.
|
53
53
|
"""
|
54
|
-
|
54
|
+
if isinstance(version, str):
|
55
|
+
splits = version.split(".", 1)
|
56
|
+
else:
|
57
|
+
splits = []
|
55
58
|
if len(splits) != 2:
|
56
59
|
raise ValueError(f"Invalid version: {version}")
|
57
60
|
if not splits[0].isdigit() or not splits[1].isdigit():
|