openepd 7.1.0__py3-none-any.whl → 7.3.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/__version__.py +1 -1
- openepd/api/average_dataset/generic_estimate_sync_api.py +2 -1
- openepd/api/average_dataset/industry_epd_sync_api.py +2 -1
- openepd/api/base_sync_client.py +10 -8
- openepd/api/common.py +17 -11
- openepd/api/dto/common.py +1 -1
- openepd/api/epd/sync_api.py +2 -1
- openepd/api/org/__init__.py +15 -0
- openepd/api/org/sync_api.py +79 -0
- openepd/api/pcr/sync_api.py +35 -0
- openepd/api/plant/__init__.py +15 -0
- openepd/api/plant/sync_api.py +79 -0
- openepd/api/standard/__init__.py +15 -0
- openepd/api/standard/sync_api.py +79 -0
- openepd/api/sync_client.py +27 -0
- openepd/bundle/base.py +47 -6
- openepd/bundle/model.py +1 -0
- openepd/bundle/reader.py +35 -10
- openepd/bundle/writer.py +21 -12
- openepd/m49/__init__.py +2 -0
- openepd/m49/const.py +1 -1
- openepd/m49/utils.py +16 -10
- openepd/model/base.py +20 -15
- openepd/model/common.py +10 -5
- openepd/model/declaration.py +2 -2
- openepd/model/epd.py +2 -1
- openepd/model/factory.py +5 -3
- openepd/model/generic_estimate.py +4 -0
- openepd/model/lcia.py +10 -10
- openepd/model/org.py +14 -7
- openepd/model/pcr.py +2 -2
- openepd/model/specs/__init__.py +37 -0
- openepd/model/specs/asphalt.py +3 -3
- openepd/model/specs/base.py +2 -1
- openepd/model/specs/enums.py +9 -1
- openepd/model/specs/range/__init__.py +5 -3
- openepd/model/specs/range/accessories.py +1 -1
- openepd/model/specs/range/aluminium.py +1 -1
- openepd/model/specs/range/cladding.py +10 -10
- openepd/model/specs/range/cmu.py +0 -2
- openepd/model/specs/range/concrete.py +25 -2
- openepd/model/specs/range/conveying_equipment.py +2 -2
- openepd/model/specs/range/electrical.py +18 -18
- openepd/model/specs/range/electrical_transmission_and_distribution_equipment.py +1 -1
- openepd/model/specs/range/exterior_improvements.py +47 -0
- openepd/model/specs/range/finishes.py +19 -40
- openepd/model/specs/range/fire_and_smoke_protection.py +3 -3
- openepd/model/specs/range/furnishings.py +7 -7
- openepd/model/specs/range/manufacturing_inputs.py +17 -5
- openepd/model/specs/range/masonry.py +1 -1
- openepd/model/specs/range/mechanical.py +6 -6
- openepd/model/specs/range/mixins/__init__.py +15 -0
- openepd/model/specs/range/mixins/access_flooring_mixin.py +43 -0
- openepd/model/specs/range/network_infrastructure.py +3 -3
- openepd/model/specs/range/openings.py +17 -17
- openepd/model/specs/range/other_materials.py +4 -4
- openepd/model/specs/range/plumbing.py +5 -5
- openepd/model/specs/range/precast_concrete.py +2 -2
- openepd/model/specs/range/steel.py +18 -9
- openepd/model/specs/range/thermal_moisture_protection.py +12 -12
- openepd/model/specs/range/wood.py +4 -6
- openepd/model/specs/singular/__init__.py +119 -2
- openepd/model/specs/singular/aluminium.py +2 -1
- openepd/model/specs/singular/concrete.py +25 -1
- openepd/model/specs/singular/deprecated/__init__.py +1 -1
- openepd/model/specs/singular/exterior_improvements.py +47 -0
- openepd/model/specs/singular/finishes.py +3 -59
- openepd/model/specs/singular/manufacturing_inputs.py +13 -1
- openepd/model/specs/singular/mixins/access_flooring_mixin.py +55 -0
- openepd/model/specs/singular/steel.py +10 -2
- openepd/model/validation/common.py +10 -6
- openepd/model/validation/enum.py +4 -2
- openepd/model/validation/quantity.py +13 -6
- openepd/model/versioning.py +8 -6
- {openepd-7.1.0.dist-info → openepd-7.3.0.dist-info}/METADATA +23 -13
- {openepd-7.1.0.dist-info → openepd-7.3.0.dist-info}/RECORD +78 -67
- {openepd-7.1.0.dist-info → openepd-7.3.0.dist-info}/WHEEL +1 -1
- {openepd-7.1.0.dist-info → openepd-7.3.0.dist-info}/LICENSE +0 -0
@@ -17,10 +17,6 @@ import pydantic
|
|
17
17
|
|
18
18
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
|
19
19
|
from openepd.model.specs.enums import (
|
20
|
-
AccessFlooringCoreMaterial,
|
21
|
-
AccessFlooringFinishMaterial,
|
22
|
-
AccessFlooringSeismicRating,
|
23
|
-
AccessFlooringStringers,
|
24
20
|
AllFabrication,
|
25
21
|
CarpetFormFactor,
|
26
22
|
CarpetIntendedApplication,
|
@@ -44,13 +40,12 @@ from openepd.model.specs.enums import (
|
|
44
40
|
WoodFlooringTimberSpecies,
|
45
41
|
)
|
46
42
|
from openepd.model.specs.singular.common import HasForestPracticesCertifiers
|
43
|
+
from openepd.model.specs.singular.mixins.access_flooring_mixin import AccessFlooringMixin
|
47
44
|
from openepd.model.validation.quantity import (
|
48
45
|
AreaPerVolumeStr,
|
49
|
-
ForceNStr,
|
50
46
|
GwpKgCo2eStr,
|
51
47
|
LengthMmStr,
|
52
48
|
LengthMStr,
|
53
|
-
PressureMPaStr,
|
54
49
|
RFactorStr,
|
55
50
|
YarnWeightStr,
|
56
51
|
validate_quantity_ge_factory,
|
@@ -59,7 +54,7 @@ from openepd.model.validation.quantity import (
|
|
59
54
|
)
|
60
55
|
|
61
56
|
|
62
|
-
class AccessFlooringV1(BaseOpenEpdHierarchicalSpec):
|
57
|
+
class AccessFlooringV1(BaseOpenEpdHierarchicalSpec, AccessFlooringMixin):
|
63
58
|
"""
|
64
59
|
Elevated floor system built on top of concrete slab surface.
|
65
60
|
|
@@ -69,57 +64,6 @@ class AccessFlooringV1(BaseOpenEpdHierarchicalSpec):
|
|
69
64
|
|
70
65
|
_EXT_VERSION = "1.0"
|
71
66
|
|
72
|
-
# Own fields:
|
73
|
-
core_material: AccessFlooringCoreMaterial | None = pydantic.Field(
|
74
|
-
default=None, description="", examples=["Cementitious"]
|
75
|
-
)
|
76
|
-
finish_material: AccessFlooringFinishMaterial | None = pydantic.Field(
|
77
|
-
default=None, description="", examples=["Linoleum"]
|
78
|
-
)
|
79
|
-
stringers: AccessFlooringStringers | None = pydantic.Field(default=None, description="", examples=["Standard"])
|
80
|
-
seismic_rating: AccessFlooringSeismicRating | None = pydantic.Field(
|
81
|
-
default=None, description="", examples=["Type 0"]
|
82
|
-
)
|
83
|
-
magnetically_attached_finish: bool | None = pydantic.Field(
|
84
|
-
default=None,
|
85
|
-
description="",
|
86
|
-
examples=[True],
|
87
|
-
)
|
88
|
-
permanent_finish: bool | None = pydantic.Field(
|
89
|
-
default=None,
|
90
|
-
description="",
|
91
|
-
examples=[True],
|
92
|
-
)
|
93
|
-
drylay: bool | None = pydantic.Field(
|
94
|
-
default=None,
|
95
|
-
description="",
|
96
|
-
examples=[True],
|
97
|
-
)
|
98
|
-
adjustable_height: bool | None = pydantic.Field(
|
99
|
-
default=None,
|
100
|
-
description="",
|
101
|
-
examples=[True],
|
102
|
-
)
|
103
|
-
fixed_height: bool | None = pydantic.Field(
|
104
|
-
default=None,
|
105
|
-
description="",
|
106
|
-
examples=[True],
|
107
|
-
)
|
108
|
-
finished_floor_height: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["1 m"])
|
109
|
-
panel_thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["1 m"])
|
110
|
-
concentrated_load: PressureMPaStr | None = pydantic.Field(default=None, description="", examples=["1 MPa"])
|
111
|
-
uniform_load: PressureMPaStr | None = pydantic.Field(default=None, description="", examples=["1 MPa"])
|
112
|
-
rolling_load_10_pass: ForceNStr | None = pydantic.Field(default=None, description="", examples=["1 N"])
|
113
|
-
rolling_load_10000_pass: ForceNStr | None = pydantic.Field(default=None, description="", examples=["1 N"])
|
114
|
-
|
115
|
-
@pydantic.field_validator("rolling_load_10_pass", mode="before", check_fields=False)
|
116
|
-
def _access_flooring_rolling_load_10_pass_is_quantity_validator(cls, value):
|
117
|
-
return validate_quantity_unit_factory("N")(cls, value)
|
118
|
-
|
119
|
-
@pydantic.field_validator("rolling_load_10000_pass", mode="before", check_fields=False)
|
120
|
-
def _access_flooring_rolling_load_10000_pass_is_quantity_validator(cls, value):
|
121
|
-
return validate_quantity_unit_factory("N")(cls, value)
|
122
|
-
|
123
67
|
|
124
68
|
class CarpetV1(BaseOpenEpdHierarchicalSpec):
|
125
69
|
"""Textile Floor Coverings."""
|
@@ -419,7 +363,7 @@ class BackingAndUnderlayV1(BaseOpenEpdHierarchicalSpec):
|
|
419
363
|
class CementBoardV1(BaseOpenEpdHierarchicalSpec):
|
420
364
|
"""Hard cementitious boards, typically used as a tile backer."""
|
421
365
|
|
422
|
-
_EXT_VERSION = "1.
|
366
|
+
_EXT_VERSION = "1.1"
|
423
367
|
|
424
368
|
# Own fields:
|
425
369
|
thickness: CementBoardThickness | None = pydantic.Field(
|
@@ -28,6 +28,7 @@ from openepd.model.specs.enums import (
|
|
28
28
|
MasonryCementAstmC91Type,
|
29
29
|
TextilesFabricType,
|
30
30
|
)
|
31
|
+
from openepd.model.specs.singular.mixins.access_flooring_mixin import AccessFlooringMixin
|
31
32
|
|
32
33
|
|
33
34
|
class CementV1(BaseOpenEpdHierarchicalSpec):
|
@@ -141,6 +142,16 @@ class TextilesV1(BaseOpenEpdHierarchicalSpec):
|
|
141
142
|
fabric_type: list[TextilesFabricType] | None = pydantic.Field(default=None, description="", examples=[["Leather"]])
|
142
143
|
|
143
144
|
|
145
|
+
class AccessFlooringPanelsV1(BaseOpenEpdHierarchicalSpec, AccessFlooringMixin):
|
146
|
+
"""
|
147
|
+
Part of an access floor system.
|
148
|
+
|
149
|
+
Panels are laid on top of an access floor pedestal, creating a finish floor.
|
150
|
+
"""
|
151
|
+
|
152
|
+
_EXT_VERSION = "1.0"
|
153
|
+
|
154
|
+
|
144
155
|
class ManufacturingInputsV1(BaseOpenEpdHierarchicalSpec):
|
145
156
|
"""
|
146
157
|
Manufacturing inputs.
|
@@ -149,7 +160,7 @@ class ManufacturingInputsV1(BaseOpenEpdHierarchicalSpec):
|
|
149
160
|
a construction.
|
150
161
|
"""
|
151
162
|
|
152
|
-
_EXT_VERSION = "1.
|
163
|
+
_EXT_VERSION = "1.1"
|
153
164
|
|
154
165
|
# Nested specs:
|
155
166
|
AccessFlooringPedestals: AccessFlooringPedestalsV1 | None = None
|
@@ -158,3 +169,4 @@ class ManufacturingInputsV1(BaseOpenEpdHierarchicalSpec):
|
|
158
169
|
CementitiousMaterials: CementitiousMaterialsV1 | None = None
|
159
170
|
ConcreteAdmixtures: ConcreteAdmixturesV1 | None = None
|
160
171
|
Textiles: TextilesV1 | None = None
|
172
|
+
AccessFlooringPanels: AccessFlooringPanelsV1 | None = None
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2025 by C Change Labs Inc. www.c-change-labs.com
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
import pydantic as pyd
|
17
|
+
|
18
|
+
from openepd.model.specs.base import BaseOpenEpdSpec
|
19
|
+
from openepd.model.specs.enums import (
|
20
|
+
AccessFlooringCoreMaterial,
|
21
|
+
AccessFlooringFinishMaterial,
|
22
|
+
AccessFlooringSeismicRating,
|
23
|
+
AccessFlooringStringers,
|
24
|
+
)
|
25
|
+
from openepd.model.validation.quantity import ForceNStr, LengthMmStr, PressureMPaStr, validate_quantity_unit_factory
|
26
|
+
|
27
|
+
|
28
|
+
class AccessFlooringMixin(BaseOpenEpdSpec):
|
29
|
+
core_material: AccessFlooringCoreMaterial | None = pyd.Field(
|
30
|
+
default=None, description="", examples=["Cementitious"]
|
31
|
+
)
|
32
|
+
finish_material: AccessFlooringFinishMaterial | None = pyd.Field(
|
33
|
+
default=None, description="", examples=["Linoleum"]
|
34
|
+
)
|
35
|
+
stringers: AccessFlooringStringers | None = pyd.Field(default=None, description="", examples=["Standard"])
|
36
|
+
seismic_rating: AccessFlooringSeismicRating | None = pyd.Field(default=None, description="", examples=["Type 0"])
|
37
|
+
magnetically_attached_finish: bool | None = pyd.Field(default=None, description="", examples=[True])
|
38
|
+
permanent_finish: bool | None = pyd.Field(default=None, description="", examples=[True])
|
39
|
+
drylay: bool | None = pyd.Field(default=None, description="", examples=[True])
|
40
|
+
adjustable_height: bool | None = pyd.Field(default=None, description="", examples=[True])
|
41
|
+
fixed_height: bool | None = pyd.Field(default=None, description="", examples=[True])
|
42
|
+
finished_floor_height: LengthMmStr | None = pyd.Field(default=None, description="", examples=["1 m"])
|
43
|
+
panel_thickness: LengthMmStr | None = pyd.Field(default=None, description="", examples=["1 m"])
|
44
|
+
concentrated_load: PressureMPaStr | None = pyd.Field(default=None, description="", examples=["1 MPa"])
|
45
|
+
uniform_load: PressureMPaStr | None = pyd.Field(default=None, description="", examples=["1 MPa"])
|
46
|
+
rolling_load_10_pass: ForceNStr | None = pyd.Field(default=None, description="", examples=["1 N"])
|
47
|
+
rolling_load_10000_pass: ForceNStr | None = pyd.Field(default=None, description="", examples=["1 N"])
|
48
|
+
|
49
|
+
@pyd.field_validator("rolling_load_10_pass", mode="before", check_fields=False)
|
50
|
+
def _access_flooring_rolling_load_10_pass_is_quantity_validator(cls, value):
|
51
|
+
return validate_quantity_unit_factory("N")(cls, value)
|
52
|
+
|
53
|
+
@pyd.field_validator("rolling_load_10000_pass", mode="before", check_fields=False)
|
54
|
+
def _access_flooring_rolling_load_10000_pass_is_quantity_validator(cls, value):
|
55
|
+
return validate_quantity_unit_factory("N")(cls, value)
|
@@ -89,7 +89,8 @@ class HotRolledSectionsV1(BaseOpenEpdHierarchicalSpec, SteelFabricatedMixin):
|
|
89
89
|
|
90
90
|
|
91
91
|
class PlateSteelV1(BaseOpenEpdHierarchicalSpec, SteelFabricatedMixin):
|
92
|
-
"""
|
92
|
+
"""
|
93
|
+
Plate Steels.
|
93
94
|
|
94
95
|
Flat hot-rolled steel, typically thicker than 'sheet', made by compressing multiple steel
|
95
96
|
layers together into one.
|
@@ -260,10 +261,16 @@ class OtherSteelV1(BaseOpenEpdHierarchicalSpec):
|
|
260
261
|
_EXT_VERSION = "1.0"
|
261
262
|
|
262
263
|
|
264
|
+
class CrudeSteelV1(BaseOpenEpdHierarchicalSpec):
|
265
|
+
"""Steel ingots, billets, blooms, and slabs for use in manufacturing steel products."""
|
266
|
+
|
267
|
+
_EXT_VERSION = "1.0"
|
268
|
+
|
269
|
+
|
263
270
|
class SteelV1(BaseOpenEpdHierarchicalSpec):
|
264
271
|
"""Broad category for construction materials made from steel and its alloys."""
|
265
272
|
|
266
|
-
_EXT_VERSION = "1.
|
273
|
+
_EXT_VERSION = "1.2"
|
267
274
|
|
268
275
|
# Own fields:
|
269
276
|
yield_tensile_str: PressureMPaStr | None = pydantic.Field(
|
@@ -327,3 +334,4 @@ class SteelV1(BaseOpenEpdHierarchicalSpec):
|
|
327
334
|
RebarSteel: RebarSteelV1 | None = None
|
328
335
|
WireMeshSteel: WireMeshSteelV1 | None = None
|
329
336
|
OtherSteel: OtherSteelV1 | None = None
|
337
|
+
CrudeSteel: CrudeSteelV1 | None = None
|
@@ -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
|
-
from
|
16
|
+
from collections.abc import Callable
|
17
|
+
from typing import Annotated, Any, TypeAlias
|
17
18
|
|
18
19
|
import pydantic
|
19
20
|
|
@@ -25,7 +26,8 @@ def together_validator(field1: str, field2: Any, values: dict[str, Any]) -> Any:
|
|
25
26
|
value1 = values.get(field1)
|
26
27
|
value2 = values.get(field2)
|
27
28
|
if value1 is not None and value2 is None or value1 is None and value2 is not None:
|
28
|
-
|
29
|
+
msg = f"Both or neither {field1} and {field2} days must be provided together"
|
30
|
+
raise ValueError(msg)
|
29
31
|
|
30
32
|
|
31
33
|
def validate_version_format(v: str) -> str:
|
@@ -36,17 +38,19 @@ def validate_version_format(v: str) -> str:
|
|
36
38
|
|
37
39
|
def validate_version_compatibility(
|
38
40
|
class_version_attribute_name: str,
|
39
|
-
) -> Callable[[
|
41
|
+
) -> Callable[[type, str], str]:
|
40
42
|
"""Ensure that the object which is passed for parsing and validation is compatible with the class."""
|
41
43
|
|
42
44
|
# we need closure to pass property name, since actual class will only be available in runtime
|
43
|
-
def internal_validate_version_compatibility(cls:
|
45
|
+
def internal_validate_version_compatibility(cls: type, v: str) -> str:
|
44
46
|
if not hasattr(cls, class_version_attribute_name):
|
45
|
-
|
47
|
+
msg = f"Class {cls} must declare a class var extension var named {class_version_attribute_name}"
|
48
|
+
raise ValueError(msg)
|
46
49
|
|
47
50
|
class_version = getattr(cls, class_version_attribute_name)
|
48
51
|
if Version.parse_version(v).major != Version.parse_version(class_version).major:
|
49
|
-
|
52
|
+
msg = f"Extension version {v} does not match class version {class_version}"
|
53
|
+
raise ValueError(msg)
|
50
54
|
return v
|
51
55
|
|
52
56
|
return internal_validate_version_compatibility
|
openepd/model/validation/enum.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
|
-
from
|
16
|
+
from collections.abc import Callable
|
17
|
+
from typing import Any
|
17
18
|
|
18
19
|
from openepd.model.common import EnumGroupingAware
|
19
20
|
|
@@ -35,7 +36,8 @@ def exclusive_groups_validator_factory(enum_type: type[EnumGroupingAware]) -> Ca
|
|
35
36
|
for grouping in enum_type.get_groupings():
|
36
37
|
matching_from_group = [v for v in (value or []) if v in grouping]
|
37
38
|
if len(matching_from_group) > 1:
|
38
|
-
|
39
|
+
msg = f"Values {', '.join(matching_from_group)} are not allowed together."
|
40
|
+
raise ValueError(msg)
|
39
41
|
|
40
42
|
return value
|
41
43
|
|
@@ -14,12 +14,12 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
from abc import ABC, abstractmethod
|
17
|
-
from
|
17
|
+
from collections.abc import Callable
|
18
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Self
|
18
19
|
|
19
20
|
import pydantic
|
20
21
|
from pydantic import ConfigDict
|
21
22
|
import pydantic_core
|
22
|
-
from typing_extensions import Self
|
23
23
|
|
24
24
|
from openepd.model.base import BaseOpenEpdSchema
|
25
25
|
from openepd.model.common import Amount, OpenEPDUnit, RangeAmount
|
@@ -59,8 +59,10 @@ class QuantityValidator(ABC):
|
|
59
59
|
dimensionality: The dimensionality to validate against, like "kg"
|
60
60
|
Returns:
|
61
61
|
None if the value is valid, raises an error otherwise.
|
62
|
+
|
62
63
|
Raises:
|
63
64
|
ValueError: If the value is not valid.
|
65
|
+
|
64
66
|
"""
|
65
67
|
pass
|
66
68
|
|
@@ -74,8 +76,10 @@ class QuantityValidator(ABC):
|
|
74
76
|
min_value: The value to compare with, like "102.4 kg"
|
75
77
|
Returns:
|
76
78
|
None if the value is valid, raises an error otherwise.
|
79
|
+
|
77
80
|
Raises:
|
78
81
|
ValueError: If the value is not valid.
|
82
|
+
|
79
83
|
"""
|
80
84
|
pass
|
81
85
|
|
@@ -89,8 +93,10 @@ class QuantityValidator(ABC):
|
|
89
93
|
max_value: The value to compare with, like "0.4 kg"
|
90
94
|
Returns:
|
91
95
|
None if the value is valid, raises an error otherwise.
|
96
|
+
|
92
97
|
Raises:
|
93
98
|
ValueError: If the value is not valid.
|
99
|
+
|
94
100
|
"""
|
95
101
|
pass
|
96
102
|
|
@@ -168,10 +174,10 @@ class QuantityStr(str):
|
|
168
174
|
unit: ClassVar[str]
|
169
175
|
|
170
176
|
@classmethod
|
171
|
-
def _validate(cls, value: str) ->
|
177
|
+
def _validate(cls, value: str) -> Self:
|
172
178
|
value = validate_quantity_unit_factory(cls.unit)(cls, value)
|
173
179
|
value = validate_quantity_ge_factory(f"0 {cls.unit}")(cls, value)
|
174
|
-
return value
|
180
|
+
return cls(value)
|
175
181
|
|
176
182
|
@classmethod
|
177
183
|
def __get_pydantic_core_schema__(
|
@@ -389,7 +395,8 @@ class WithDimensionalityMixin(BaseOpenEpdSchema):
|
|
389
395
|
return self
|
390
396
|
|
391
397
|
if self.unit is None:
|
392
|
-
|
398
|
+
msg = "`unit` is required for dimensionality-validated amounts"
|
399
|
+
raise ValueError(msg)
|
393
400
|
|
394
401
|
validate_unit_factory(self.dimensionality_unit)(BaseOpenEpdSchema, self.unit)
|
395
402
|
return self
|
@@ -490,7 +497,7 @@ class WithPressureMpaMixin(WithDimensionalityMixin):
|
|
490
497
|
|
491
498
|
|
492
499
|
class AmountPressureMpa(Amount, WithPressureMpaMixin):
|
493
|
-
"""
|
500
|
+
"""Pressure (MPa)."""
|
494
501
|
|
495
502
|
pass
|
496
503
|
|
openepd/model/versioning.py
CHANGED
@@ -44,7 +44,8 @@ class Version(NamedTuple):
|
|
44
44
|
|
45
45
|
@staticmethod
|
46
46
|
def parse_version(version: str | None) -> "Version":
|
47
|
-
"""
|
47
|
+
"""
|
48
|
+
Parse the version of extension or the format.
|
48
49
|
|
49
50
|
Version is expected to be major.minor
|
50
51
|
|
@@ -56,9 +57,11 @@ class Version(NamedTuple):
|
|
56
57
|
else:
|
57
58
|
splits = []
|
58
59
|
if len(splits) != 2:
|
59
|
-
|
60
|
+
msg = f"Invalid version: {version}"
|
61
|
+
raise ValueError(msg)
|
60
62
|
if not splits[0].isdigit() or not splits[1].isdigit():
|
61
|
-
|
63
|
+
msg = f"Invalid version: {version}"
|
64
|
+
raise ValueError(msg)
|
62
65
|
return Version(major=int(splits[0]), minor=int(splits[1]))
|
63
66
|
|
64
67
|
def __str__(self) -> str:
|
@@ -115,9 +118,8 @@ class OpenEpdVersions(Version, ReprEnum):
|
|
115
118
|
for x in cls:
|
116
119
|
if x.value.major == branch:
|
117
120
|
return x.value
|
118
|
-
|
119
|
-
|
120
|
-
)
|
121
|
+
msg = f"No version {branch}.x is not supported. Supported versions are: {', '.join(str(x.value) for x in cls)}"
|
122
|
+
raise ValueError(msg)
|
121
123
|
|
122
124
|
@classmethod
|
123
125
|
def get_current(cls) -> Version:
|
@@ -1,15 +1,14 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: openepd
|
3
|
-
Version: 7.
|
3
|
+
Version: 7.3.0
|
4
4
|
Summary: Python library to work with OpenEPD format
|
5
|
-
Home-page: https://github.com/cchangelabs/openepd
|
6
5
|
License: Apache-2.0
|
7
6
|
Author: C-Change Labs
|
8
7
|
Author-email: support@c-change-labs.com
|
9
8
|
Maintainer: C-Change Labs
|
10
9
|
Maintainer-email: open-source@c-change-labs.com
|
11
10
|
Requires-Python: >=3.11,<4.0
|
12
|
-
Classifier: Development Status ::
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
13
12
|
Classifier: Intended Audience :: Developers
|
14
13
|
Classifier: License :: OSI Approved :: Apache Software License
|
15
14
|
Classifier: Operating System :: OS Independent
|
@@ -21,7 +20,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
20
|
Provides-Extra: api-client
|
22
21
|
Requires-Dist: email-validator (>=1.3.1)
|
23
22
|
Requires-Dist: idna (>=3.7)
|
24
|
-
Requires-Dist: open-xpd-uuid (>=0.2.1,<
|
23
|
+
Requires-Dist: open-xpd-uuid (>=0.2.1,<2)
|
25
24
|
Requires-Dist: openlocationcode (>=1.0.1)
|
26
25
|
Requires-Dist: pydantic (>=2.0,<3)
|
27
26
|
Requires-Dist: requests (>=2.0) ; extra == "api-client"
|
@@ -45,6 +44,24 @@ Description-Content-Type: text/markdown
|
|
45
44
|
|
46
45
|
This library is a Python library to work with OpenEPD format.
|
47
46
|
|
47
|
+
> ⚠️ **Version Warning**
|
48
|
+
>
|
49
|
+
> This application is currently developed in **two major versions** in parallel:
|
50
|
+
>
|
51
|
+
> - **v6.x (>=6.0.0)** — Stable and production-ready. Maintains support for Pydantic v1 and v2 through a compatibility layer.
|
52
|
+
> - **v7.x (>=7.0.0)** — Public beta. Fully functional, with native support for Pydantic v2. Still experimental and may introduce breaking changes in **internal and integration interfaces**.
|
53
|
+
>
|
54
|
+
> ⚠️ No breaking changes are expected in the **public standard or data model**, only in internal APIs and integration points.
|
55
|
+
>
|
56
|
+
> Both versions currently offer the same set of features.
|
57
|
+
> We recommend using **v6** for most production use cases as the more mature and stable option.
|
58
|
+
> **v7** is suitable for production environments that can tolerate some level of interface instability and want to adopt the latest internals.
|
59
|
+
>
|
60
|
+
> 💡 Only the **latest version of v7** is guaranteed to contain all the features and updates from v6. Earlier v7 releases may lack some recent improvements.
|
61
|
+
>
|
62
|
+
> Once **v7 is promoted to stable**, all earlier **pre-stable (beta) v7 releases** will be **marked as yanked** to prevent accidental usage in production.
|
63
|
+
>
|
64
|
+
|
48
65
|
## About OpenEPD
|
49
66
|
|
50
67
|
[openEPD](https://www.buildingtransparency.org/programs/openepd/) is an open data format for passing digital
|
@@ -60,17 +77,10 @@ including uniqueness of organizations/plants, precise PCR references, and dated
|
|
60
77
|
The openEPD format is **extensible**. Standard extensions exist for concrete products, and for
|
61
78
|
documenting supply-chain specific data.
|
62
79
|
|
63
|
-
[Read More about OpenEPD format here](https://www.
|
80
|
+
[Read More about OpenEPD format here](https://www.open-epd-forum.org).
|
64
81
|
|
65
82
|
## Usage
|
66
83
|
|
67
|
-
**❗ ATTENTION**: Pick the right version. The cornerstone of this library models package representing openEPD models.
|
68
|
-
Models are defined with Pydantic library which is a dependency for openepd package. If you use Pydantic in your project
|
69
|
-
carefully pick the version:
|
70
|
-
|
71
|
-
* Use version **below** `2.0.0` if your project uses Pydantic version below `2.0.0`
|
72
|
-
* Use version `2.x.x` or higher if your project uses Pydantic version `2.0.0` or above
|
73
|
-
|
74
84
|
### Models
|
75
85
|
|
76
86
|
The library provides the Pydantic models for all the OpenEPD entities. The models are available in the `openepd.models`
|