openepd 6.13.1__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.
Files changed (102) hide show
  1. openepd/__init__.py +4 -4
  2. openepd/__version__.py +1 -1
  3. openepd/api/average_dataset/generic_estimate_sync_api.py +11 -10
  4. openepd/api/average_dataset/industry_epd_sync_api.py +9 -8
  5. openepd/api/base_sync_client.py +53 -9
  6. openepd/api/category/sync_api.py +1 -1
  7. openepd/api/dto/base.py +4 -4
  8. openepd/api/dto/common.py +24 -16
  9. openepd/api/dto/meta.py +15 -11
  10. openepd/api/dto/mf.py +9 -8
  11. openepd/api/epd/dto.py +43 -33
  12. openepd/api/epd/sync_api.py +9 -9
  13. openepd/api/pcr/sync_api.py +2 -2
  14. openepd/bundle/model.py +11 -10
  15. openepd/bundle/reader.py +12 -5
  16. openepd/bundle/writer.py +17 -6
  17. openepd/m49/__init__.py +2 -0
  18. openepd/m49/const.py +5 -2
  19. openepd/m49/{geo_converter.py → utils.py} +24 -2
  20. openepd/model/base.py +60 -43
  21. openepd/model/category.py +13 -10
  22. openepd/model/common.py +100 -55
  23. openepd/model/declaration.py +93 -64
  24. openepd/model/epd.py +51 -43
  25. openepd/model/generic_estimate.py +28 -13
  26. openepd/model/industry_epd.py +15 -9
  27. openepd/model/lcia.py +132 -113
  28. openepd/model/org.py +54 -33
  29. openepd/model/pcr.py +38 -32
  30. openepd/model/specs/asphalt.py +31 -22
  31. openepd/model/specs/base.py +11 -9
  32. openepd/model/specs/concrete.py +60 -39
  33. openepd/model/specs/range/aggregates.py +9 -9
  34. openepd/model/specs/range/aluminium.py +7 -7
  35. openepd/model/specs/range/asphalt.py +22 -19
  36. openepd/model/specs/range/cladding.py +16 -16
  37. openepd/model/specs/range/cmu.py +10 -9
  38. openepd/model/specs/range/concrete.py +36 -27
  39. openepd/model/specs/range/conveying_equipment.py +16 -15
  40. openepd/model/specs/range/electrical.py +24 -22
  41. openepd/model/specs/range/finishes.py +109 -104
  42. openepd/model/specs/range/fire_and_smoke_protection.py +7 -7
  43. openepd/model/specs/range/furnishings.py +16 -12
  44. openepd/model/specs/range/manufacturing_inputs.py +16 -16
  45. openepd/model/specs/range/masonry.py +16 -16
  46. openepd/model/specs/range/mechanical.py +47 -47
  47. openepd/model/specs/range/mechanical_insulation.py +7 -7
  48. openepd/model/specs/range/network_infrastructure.py +54 -46
  49. openepd/model/specs/range/openings.py +36 -31
  50. openepd/model/specs/range/plumbing.py +15 -13
  51. openepd/model/specs/range/precast_concrete.py +20 -16
  52. openepd/model/specs/range/sheathing.py +18 -18
  53. openepd/model/specs/range/steel.py +25 -25
  54. openepd/model/specs/range/thermal_moisture_protection.py +20 -20
  55. openepd/model/specs/range/utility_piping.py +9 -9
  56. openepd/model/specs/range/wood.py +19 -19
  57. openepd/model/specs/range/wood_joists.py +8 -8
  58. openepd/model/specs/singular/__init__.py +9 -5
  59. openepd/model/specs/singular/aggregates.py +22 -15
  60. openepd/model/specs/singular/aluminium.py +20 -5
  61. openepd/model/specs/singular/asphalt.py +44 -20
  62. openepd/model/specs/singular/cladding.py +38 -23
  63. openepd/model/specs/singular/cmu.py +26 -11
  64. openepd/model/specs/singular/common.py +3 -2
  65. openepd/model/specs/singular/concrete.py +85 -48
  66. openepd/model/specs/singular/conveying_equipment.py +30 -17
  67. openepd/model/specs/singular/deprecated/__init__.py +3 -2
  68. openepd/model/specs/singular/deprecated/concrete.py +68 -33
  69. openepd/model/specs/singular/deprecated/steel.py +28 -15
  70. openepd/model/specs/singular/electrical.py +69 -41
  71. openepd/model/specs/singular/finishes.py +250 -140
  72. openepd/model/specs/singular/fire_and_smoke_protection.py +9 -6
  73. openepd/model/specs/singular/furnishings.py +16 -14
  74. openepd/model/specs/singular/manufacturing_inputs.py +23 -14
  75. openepd/model/specs/singular/masonry.py +66 -21
  76. openepd/model/specs/singular/mechanical.py +48 -47
  77. openepd/model/specs/singular/mechanical_insulation.py +7 -6
  78. openepd/model/specs/singular/mixins/conduit_mixin.py +13 -10
  79. openepd/model/specs/singular/network_infrastructure.py +111 -52
  80. openepd/model/specs/singular/openings.py +127 -95
  81. openepd/model/specs/singular/plumbing.py +15 -12
  82. openepd/model/specs/singular/precast_concrete.py +68 -54
  83. openepd/model/specs/singular/sheathing.py +47 -27
  84. openepd/model/specs/singular/steel.py +69 -45
  85. openepd/model/specs/singular/thermal_moisture_protection.py +36 -20
  86. openepd/model/specs/singular/utility_piping.py +11 -8
  87. openepd/model/specs/singular/wood.py +48 -24
  88. openepd/model/specs/singular/wood_joists.py +19 -6
  89. openepd/model/standard.py +15 -8
  90. openepd/model/validation/common.py +9 -3
  91. openepd/model/validation/numbers.py +0 -13
  92. openepd/model/validation/quantity.py +53 -25
  93. openepd/model/versioning.py +9 -6
  94. openepd/patch_pydantic.py +0 -93
  95. {openepd-6.13.1.dist-info → openepd-7.0.0.dist-info}/METADATA +1 -1
  96. openepd-7.0.0.dist-info/RECORD +142 -0
  97. openepd/compat/__init__.py +0 -15
  98. openepd/compat/compat_functional_validators.py +0 -25
  99. openepd/compat/pydantic.py +0 -30
  100. openepd-6.13.1.dist-info/RECORD +0 -145
  101. {openepd-6.13.1.dist-info → openepd-7.0.0.dist-info}/LICENSE +0 -0
  102. {openepd-6.13.1.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
- from openepd.compat.pydantic import pyd
16
+ import pydantic
17
+
17
18
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
18
19
  from openepd.model.specs.enums import AluminiumAlloy
19
20
 
@@ -33,7 +34,11 @@ class AluminiumExtrusionsV1(BaseOpenEpdHierarchicalSpec):
33
34
  _EXT_VERSION = "1.0"
34
35
 
35
36
  # Own fields:
36
- thermally_improved: bool | None = pyd.Field(default=None, description="", example=True)
37
+ thermally_improved: bool | None = pydantic.Field(
38
+ default=None,
39
+ description="",
40
+ examples=[True],
41
+ )
37
42
 
38
43
 
39
44
  class AluminiumSheetGoodsV1(BaseOpenEpdHierarchicalSpec):
@@ -54,9 +59,19 @@ class AluminiumV1(BaseOpenEpdHierarchicalSpec):
54
59
  _EXT_VERSION = "1.0"
55
60
 
56
61
  # Own fields:
57
- alloy: AluminiumAlloy | None = pyd.Field(default=None, description="", example=str(AluminiumAlloy.ALLOY_1XXX))
58
- anodized: bool | None = pyd.Field(default=None, description="", example=True)
59
- painted: bool | None = pyd.Field(default=None, description="", example=True)
62
+ alloy: AluminiumAlloy | None = pydantic.Field(
63
+ default=None, description="", examples=[str(AluminiumAlloy.ALLOY_1XXX)]
64
+ )
65
+ anodized: bool | None = pydantic.Field(
66
+ default=None,
67
+ description="",
68
+ examples=[True],
69
+ )
70
+ painted: bool | None = pydantic.Field(
71
+ default=None,
72
+ description="",
73
+ examples=[True],
74
+ )
60
75
 
61
76
  # Nested specs:
62
77
  AluminiumBillets: AluminiumBilletsV1 | None = None
@@ -15,10 +15,10 @@
15
15
  #
16
16
  from typing import Annotated
17
17
 
18
- from openepd.compat.pydantic import pyd
18
+ import pydantic
19
+
19
20
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec, CodegenSpec
20
21
  from openepd.model.specs.enums import AsphaltGradation, AsphaltMixType
21
- from openepd.model.validation.numbers import RatioFloat
22
22
  from openepd.model.validation.quantity import LengthMmStr, TemperatureCStr
23
23
 
24
24
 
@@ -28,47 +28,71 @@ class AsphaltV1(BaseOpenEpdHierarchicalSpec):
28
28
  _EXT_VERSION = "1.0"
29
29
 
30
30
  # Own fields:
31
- aggregate_size_max: LengthMmStr | None = pyd.Field(default=None, description="Max aggregate size", example="20 mm")
32
- rap: RatioFloat | None = pyd.Field(
31
+ aggregate_size_max: LengthMmStr | None = pydantic.Field(
32
+ default=None, description="Max aggregate size", examples=["20 mm"]
33
+ )
34
+ rap: float | None = pydantic.Field(
33
35
  default=None,
34
36
  description="Percent of mixture that has been replaced by recycled asphalt pavement (RAP).",
35
- example=0.5,
37
+ examples=[0.5],
36
38
  ge=0,
37
39
  le=1,
38
40
  )
39
- ras: RatioFloat | None = pyd.Field(
41
+ ras: float | None = pydantic.Field(
40
42
  default=None,
41
43
  description="Percent of mixture that has been replaced by recycled asphalt shingles (RAS).",
42
- example=0.5,
44
+ examples=[0.5],
43
45
  ge=0,
44
46
  le=1,
45
47
  )
46
- ground_tire_rubber: RatioFloat | None = pyd.Field(
48
+ ground_tire_rubber: float | None = pydantic.Field(
47
49
  default=None,
48
50
  description="Percent of mixture that has been replaced by ground tire rubber (GTR).",
49
- example=0.5,
51
+ examples=[0.5],
50
52
  ge=0,
51
53
  le=1,
52
54
  )
53
- max_temperature: Annotated[TemperatureCStr | None, CodegenSpec(override_type=TemperatureCStr)] = pyd.Field(
55
+ max_temperature: Annotated[TemperatureCStr | None, CodegenSpec(override_type=TemperatureCStr)] = pydantic.Field(
54
56
  default=None,
55
57
  description="The upper threshold temperature to which an asphalt "
56
58
  "binder can be heated preventing the asphalt mixture "
57
59
  "from rutting",
58
- example="90 °C",
60
+ examples=["90 °C"],
59
61
  )
60
- min_temperature: Annotated[TemperatureCStr | None, CodegenSpec(override_type=TemperatureCStr)] = pyd.Field(
62
+ min_temperature: Annotated[TemperatureCStr | None, CodegenSpec(override_type=TemperatureCStr)] = pydantic.Field(
61
63
  default=None,
62
64
  description="The lower threshold temperature for an asphalt "
63
65
  "binder to prevent thermal cracking of the asphalt"
64
66
  " mixture.",
65
- example="-20 °C",
67
+ examples=["-20 °C"],
68
+ )
69
+ mix_type: AsphaltMixType | None = pydantic.Field(default=None, description="Asphalt mix type", examples=["WMA"])
70
+ gradation: AsphaltGradation | None = pydantic.Field(
71
+ default=None, description="Asphalt gradation", examples=["Gap-graded"]
66
72
  )
67
- mix_type: AsphaltMixType | None = pyd.Field(default=None, description="Asphalt mix type", example="WMA")
68
- gradation: AsphaltGradation | None = pyd.Field(default=None, description="Asphalt gradation", example="Gap-graded")
69
73
 
70
- sbr: bool | None = pyd.Field(default=None, description="Styrene-butadiene rubber (SBR)", example=True)
71
- sbs: bool | None = pyd.Field(default=None, description="Styrene-butadiene-styrene (SBS)", example=True)
72
- ppa: bool | None = pyd.Field(default=None, description="Polyphosphoric acid (PPA)", example=True)
73
- gtr: bool | None = pyd.Field(default=None, description="Ground tire rubber (GTR)", example=True)
74
- pmb: bool | None = pyd.Field(default=None, description="Polymer modified bitumen (PMB)", example=True)
74
+ sbr: bool | None = pydantic.Field(
75
+ default=None,
76
+ description="Styrene-butadiene rubber (SBR)",
77
+ examples=[True],
78
+ )
79
+ sbs: bool | None = pydantic.Field(
80
+ default=None,
81
+ description="Styrene-butadiene-styrene (SBS)",
82
+ examples=[True],
83
+ )
84
+ ppa: bool | None = pydantic.Field(
85
+ default=None,
86
+ description="Polyphosphoric acid (PPA)",
87
+ examples=[True],
88
+ )
89
+ gtr: bool | None = pydantic.Field(
90
+ default=None,
91
+ description="Ground tire rubber (GTR)",
92
+ examples=[True],
93
+ )
94
+ pmb: bool | None = pydantic.Field(
95
+ default=None,
96
+ description="Polymer modified bitumen (PMB)",
97
+ examples=[True],
98
+ )
@@ -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 openepd.compat.pydantic import pyd
16
+ import pydantic
17
+
17
18
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
18
19
  from openepd.model.specs.enums import CladdingFacingMaterial, CladdingInsulatingMaterial, SidingFormFactor
19
20
  from openepd.model.validation.quantity import LengthMmStr, LengthMStr, RValueStr, validate_quantity_unit_factory
@@ -72,11 +73,11 @@ class InsulatedVinylSidingV1(BaseOpenEpdHierarchicalSpec):
72
73
  _EXT_VERSION = "1.0"
73
74
 
74
75
  # Own fields:
75
- thickness: LengthMmStr | None = pyd.Field(default=None, description="", example="1 mm")
76
+ thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["1 mm"])
76
77
 
77
- _vinyl_siding_thickness_is_quantity_validator = pyd.validator("thickness", allow_reuse=True)(
78
- validate_quantity_unit_factory("m")
79
- )
78
+ @pydantic.field_validator("thickness", mode="before")
79
+ def _vinyl_siding_thickness_is_quantity_validator(cls, value):
80
+ return validate_quantity_unit_factory("m")(cls, value)
80
81
 
81
82
 
82
83
  class PlywoodSidingV1(BaseOpenEpdHierarchicalSpec):
@@ -106,11 +107,11 @@ class VinylSidingV1(BaseOpenEpdHierarchicalSpec):
106
107
  _EXT_VERSION = "1.0"
107
108
 
108
109
  # Own fields:
109
- thickness: LengthMmStr | None = pyd.Field(default=None, description="", example="5 mm")
110
+ thickness: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["5 mm"])
110
111
 
111
- _vinyl_siding_thickness_is_quantity_validator = pyd.validator("thickness", allow_reuse=True)(
112
- validate_quantity_unit_factory("m")
113
- )
112
+ @pydantic.field_validator("thickness")
113
+ def _vinyl_siding_thickness_is_quantity_validator(cls, value):
114
+ return validate_quantity_unit_factory("m")(cls, value)
114
115
 
115
116
 
116
117
  class SidingV1(BaseOpenEpdHierarchicalSpec):
@@ -123,11 +124,23 @@ class SidingV1(BaseOpenEpdHierarchicalSpec):
123
124
  _EXT_VERSION = "1.0"
124
125
 
125
126
  # Own fields:
126
- insulated: bool | None = pyd.Field(default=None, description="", example=True)
127
- ventilated: bool | None = pyd.Field(default=None, description="", example=True)
128
- paint_or_stain_required: bool | None = pyd.Field(default=None, description="", example=True)
129
- r_value: RValueStr | None = pyd.Field(default=None, description="")
130
- form_factor: SidingFormFactor | None = pyd.Field(default=None, description="", example="Lap")
127
+ insulated: bool | None = pydantic.Field(
128
+ default=None,
129
+ description="",
130
+ examples=[True],
131
+ )
132
+ ventilated: bool | None = pydantic.Field(
133
+ default=None,
134
+ description="",
135
+ examples=[True],
136
+ )
137
+ paint_or_stain_required: bool | None = pydantic.Field(
138
+ default=None,
139
+ description="",
140
+ examples=[True],
141
+ )
142
+ r_value: RValueStr | None = pydantic.Field(default=None, description="")
143
+ form_factor: SidingFormFactor | None = pydantic.Field(default=None, description="", examples=["Lap"])
131
144
 
132
145
  # Nested specs:
133
146
  MetalSiding: MetalSidingV1 | None = None
@@ -146,9 +159,9 @@ class InsulatedRoofPanelsV1(BaseOpenEpdHierarchicalSpec):
146
159
  _EXT_VERSION = "1.0"
147
160
 
148
161
  # Own fields:
149
- r_value: RValueStr | None = pyd.Field(default=None, description="")
150
- insulating_material: CladdingInsulatingMaterial | None = pyd.Field(
151
- default=None, description="", example="No Insulation"
162
+ r_value: RValueStr | None = pydantic.Field(default=None, description="")
163
+ insulating_material: CladdingInsulatingMaterial | None = pydantic.Field(
164
+ default=None, description="", examples=["No Insulation"]
152
165
  )
153
166
 
154
167
 
@@ -158,9 +171,9 @@ class InsulatedWallPanelsV1(BaseOpenEpdHierarchicalSpec):
158
171
  _EXT_VERSION = "1.0"
159
172
 
160
173
  # Own fields:
161
- r_value: RValueStr | None = pyd.Field(default=None, description="")
162
- insulating_material: CladdingInsulatingMaterial | None = pyd.Field(
163
- default=None, description="", example="No Insulation"
174
+ r_value: RValueStr | None = pydantic.Field(default=None, description="")
175
+ insulating_material: CladdingInsulatingMaterial | None = pydantic.Field(
176
+ default=None, description="", examples=["No Insulation"]
164
177
  )
165
178
 
166
179
 
@@ -188,10 +201,12 @@ class CladdingV1(BaseOpenEpdHierarchicalSpec):
188
201
  _EXT_VERSION = "1.0"
189
202
 
190
203
  # Own fields:
191
- thickness: LengthMStr | None = pyd.Field(default=None, description="", example="10 mm")
192
- facing_material: CladdingFacingMaterial | None = pyd.Field(default=None, description="", example="Steel")
204
+ thickness: LengthMStr | None = pydantic.Field(default=None, description="", examples=["10 mm"])
205
+ facing_material: CladdingFacingMaterial | None = pydantic.Field(default=None, description="", examples=["Steel"])
193
206
 
194
- _thickness_is_quantity_validator = pyd.validator("thickness", allow_reuse=True)(validate_quantity_unit_factory("m"))
207
+ @pydantic.field_validator("thickness")
208
+ def _thickness_is_quantity_validator(cls, value):
209
+ return validate_quantity_unit_factory("m")(cls, value)
195
210
 
196
211
  # Nested specs:
197
212
  Siding: SidingV1 | None = None
@@ -15,7 +15,8 @@
15
15
  #
16
16
  from typing import Annotated
17
17
 
18
- from openepd.compat.pydantic import pyd
18
+ import pydantic
19
+
19
20
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec, CodegenSpec
20
21
  from openepd.model.specs.enums import CmuBlockType, CmuWeightClassification
21
22
  from openepd.model.validation.quantity import GwpKgCo2eStr, PressureMPaStr
@@ -27,15 +28,29 @@ class CMUV1(BaseOpenEpdHierarchicalSpec):
27
28
  _EXT_VERSION = "1.0"
28
29
 
29
30
  # Own fields:
30
- white_cement: bool | None = pyd.Field(default=None, description="", example=True)
31
- strength_28d: PressureMPaStr | None = pyd.Field(default=None, description="", example="1 MPa")
32
- weight_classification: CmuWeightClassification | None = pyd.Field(default=None, description="", example="Normal")
33
- block_type: CmuBlockType | None = pyd.Field(default=None, description="", example="Gray")
34
- insulated: bool | None = pyd.Field(default=None, description="", example=True)
35
- sound_performance: bool | None = pyd.Field(default=None, description="", example=True)
36
- b1_recarbonation: Annotated[GwpKgCo2eStr | None, CodegenSpec(override_type=GwpKgCo2eStr)] = pyd.Field(
37
- default=None, description="", example="1 kgCO2e"
31
+ white_cement: bool | None = pydantic.Field(
32
+ default=None,
33
+ description="",
34
+ examples=[True],
35
+ )
36
+ strength_28d: PressureMPaStr | None = pydantic.Field(default=None, description="", examples=["1 MPa"])
37
+ weight_classification: CmuWeightClassification | None = pydantic.Field(
38
+ default=None, description="", examples=["Normal"]
39
+ )
40
+ block_type: CmuBlockType | None = pydantic.Field(default=None, description="", examples=["Gray"])
41
+ insulated: bool | None = pydantic.Field(
42
+ default=None,
43
+ description="",
44
+ examples=[True],
45
+ )
46
+ sound_performance: bool | None = pydantic.Field(
47
+ default=None,
48
+ description="",
49
+ examples=[True],
50
+ )
51
+ b1_recarbonation: Annotated[GwpKgCo2eStr | None, CodegenSpec(override_type=GwpKgCo2eStr)] = pydantic.Field(
52
+ default=None, description="", examples=["1 kgCO2e"]
38
53
  )
39
- b1_recarbonation_z: Annotated[float | None, CodegenSpec(override_type=float)] = pyd.Field(
40
- default=None, description="", example=2.3
54
+ b1_recarbonation_z: Annotated[float | None, CodegenSpec(override_type=float)] = pydantic.Field(
55
+ default=None, description="", examples=[2.3]
41
56
  )
@@ -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 openepd.compat.pydantic import pyd
16
+ import pydantic
17
+
17
18
  from openepd.model.base import BaseOpenEpdSchema
18
19
  from openepd.model.org import OrgRef
19
20
 
@@ -21,6 +22,6 @@ from openepd.model.org import OrgRef
21
22
  class HasForestPracticesCertifiers(BaseOpenEpdSchema):
22
23
  """An interface for models which are linked to forest practices certifiers."""
23
24
 
24
- forest_practices_certifiers: list[OrgRef] | None = pyd.Field(
25
+ forest_practices_certifiers: list[OrgRef] | None = pydantic.Field(
25
26
  default=None, description="List of organizations that certify forest practices."
26
27
  )
@@ -15,12 +15,12 @@
15
15
  #
16
16
  from typing import Annotated, Literal
17
17
 
18
- from openepd.compat.pydantic import pyd
18
+ import pydantic
19
+
19
20
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec, CodegenSpec
20
21
  from openepd.model.specs.concrete import Cementitious, ConcreteTypicalApplication
21
22
  from openepd.model.specs.enums import AciExposureClass, CsaExposureClass, EnExposureClass
22
23
  from openepd.model.validation.enum import exclusive_groups_validator_factory
23
- from openepd.model.validation.numbers import RatioFloat
24
24
  from openepd.model.validation.quantity import (
25
25
  LengthInchStr,
26
26
  LengthMmStr,
@@ -49,13 +49,13 @@ class ConcretePavingV1(BaseOpenEpdHierarchicalSpec):
49
49
  _EXT_VERSION = "1.0"
50
50
 
51
51
  # Own fields:
52
- flexion_strength: PressureMPaStr | None = pyd.Field(
53
- default=None, description="Concrete flexural strength.", example="30 MPa"
52
+ flexion_strength: PressureMPaStr | None = pydantic.Field(
53
+ default=None, description="Concrete flexural strength.", examples=["30 MPa"]
54
54
  )
55
55
 
56
- _concrete_flexion_strength_is_quantity_validator = pyd.validator("flexion_strength", allow_reuse=True)(
57
- validate_quantity_unit_factory("MPa")
58
- )
56
+ @pydantic.field_validator("flexion_strength", mode="before", check_fields=False)
57
+ def _validate_flexion_strength(cls, value):
58
+ return validate_quantity_unit_factory("MPa")(cls, value)
59
59
 
60
60
 
61
61
  class FlowableFillV1(BaseOpenEpdHierarchicalSpec):
@@ -110,61 +110,96 @@ class ConcreteV1(BaseOpenEpdHierarchicalSpec):
110
110
  _EXT_VERSION = "1.0"
111
111
 
112
112
  # Own fields:
113
- lightweight: bool | None = pyd.Field(default=None, description="Product is lightweight", example=True)
113
+ lightweight: bool | None = pydantic.Field(
114
+ default=None,
115
+ description="Product is lightweight",
116
+ examples=[True],
117
+ )
114
118
 
115
- strength_28d: PressureMPaStr | None = pyd.Field(
116
- default=None, description="Concrete strength after 28 days", example="1 MPa"
119
+ strength_28d: PressureMPaStr | None = pydantic.Field(
120
+ default=None, description="Concrete strength after 28 days", examples=["1 MPa"]
117
121
  )
118
- strength_other: PressureMPaStr | None = pyd.Field(
122
+ strength_other: PressureMPaStr | None = pydantic.Field(
119
123
  default=None,
120
124
  description="A strength spec which is to be reached later other 28 days (e.g. 42d)",
121
- example="30 MPa",
125
+ examples=["30 MPa"],
122
126
  )
123
127
  strength_other_d: Annotated[
124
128
  Literal[3, 7, 14, 42, 56, 72, 96, 120] | None,
125
129
  CodegenSpec(override_type=Literal[3, 7, 14, 42, 56, 72, 96, 120]),
126
- ] = pyd.Field(default=None, description="Test Day for strength_other", example=42)
130
+ ] = pydantic.Field(default=None, description="Test Day for strength_other", examples=[42])
127
131
 
128
- slump: LengthInchStr | None = pyd.Field(default=None, description="", example="2 in")
129
- min_slump: LengthInchStr | None = pyd.Field(default=None, description="Minimum test slump", example="2 in")
130
- max_slump: LengthInchStr | None = pyd.Field(default=None, description="", example="2 in")
132
+ slump: LengthInchStr | None = pydantic.Field(default=None, description="", examples=["2 in"])
133
+ min_slump: LengthInchStr | None = pydantic.Field(default=None, description="Minimum test slump", examples=["2 in"])
134
+ max_slump: LengthInchStr | None = pydantic.Field(default=None, description="", examples=["2 in"])
131
135
 
132
- min_pipeline_size: LengthMmStr | None = pyd.Field(
133
- default=None, description="Minimum pipeline size", example="200 mm"
136
+ min_pipeline_size: LengthMmStr | None = pydantic.Field(
137
+ default=None, description="Minimum pipeline size", examples=["200 mm"]
134
138
  )
135
- w_c_ratio: RatioFloat | None = pyd.Field(
136
- default=None, description="Ratio of water to cement", example=0.5, ge=0, le=1
139
+ w_c_ratio: float | None = pydantic.Field(
140
+ default=None, description="Ratio of water to cement", examples=[0.5], ge=0, le=1
141
+ )
142
+ air_entrain: bool | None = pydantic.Field(
143
+ default=None,
144
+ description="Air Entrainment",
145
+ examples=[True],
146
+ )
147
+ co2_entrain: bool | None = pydantic.Field(
148
+ default=None,
149
+ description="CO2 Curing",
150
+ examples=[True],
151
+ )
152
+ self_consolidating: bool | None = pydantic.Field(
153
+ default=None,
154
+ description="Self Compacting",
155
+ examples=[True],
156
+ )
157
+ white_cement: bool | None = pydantic.Field(
158
+ default=None,
159
+ description="White Cement",
160
+ examples=[True],
161
+ )
162
+ plc: bool | None = pydantic.Field(
163
+ default=None,
164
+ description="Portland Limestone Cement",
165
+ examples=[True],
166
+ )
167
+ finishable: bool | None = pydantic.Field(
168
+ default=None,
169
+ description="Finishable",
170
+ examples=[True],
171
+ )
172
+ fiber_reinforced: bool | None = pydantic.Field(
173
+ default=None,
174
+ description="fiber_reinforced",
175
+ examples=[True],
137
176
  )
138
- air_entrain: bool | None = pyd.Field(default=None, description="Air Entrainment", example=True)
139
- co2_entrain: bool | None = pyd.Field(default=None, description="CO2 Curing", example=True)
140
- self_consolidating: bool | None = pyd.Field(default=None, description="Self Compacting", example=True)
141
- white_cement: bool | None = pyd.Field(default=None, description="White Cement", example=True)
142
- plc: bool | None = pyd.Field(default=None, description="Portland Limestone Cement", example=True)
143
- finishable: bool | None = pyd.Field(default=None, description="Finishable", example=True)
144
- fiber_reinforced: bool | None = pyd.Field(default=None, description="fiber_reinforced", example=True)
145
177
 
146
- cementitious: Cementitious | None = pyd.Field(
147
- default=None, description="List of cementitious materials, and proportion by mass"
178
+ cementitious: Cementitious | None = pydantic.Field(
179
+ default=None,
180
+ description="List of cementitious materials, and proportion by mass",
148
181
  )
149
182
 
150
- aggregate_size_max: LengthMmStr | None = pyd.Field(
183
+ aggregate_size_max: LengthMmStr | None = pydantic.Field(
151
184
  default=None,
152
185
  description="The smallest sieve size for which the entire amount of aggregate is able to pass. "
153
186
  "Parameter describes diameter of aggregate",
154
- example="8 mm",
187
+ examples=["8 mm"],
155
188
  )
156
- cement_content: MassKgStr | None = pyd.Field(default=None, example="1 kg")
189
+ cement_content: MassKgStr | None = pydantic.Field(default=None, examples=["1 kg"])
157
190
 
158
- aci_exposure_classes: list[AciExposureClass] | None = pyd.Field(
159
- default=None, description="List of ACI exposure classes", example=["aci.F0"]
191
+ aci_exposure_classes: list[AciExposureClass] | None = pydantic.Field(
192
+ default=None, description="List of ACI exposure classes", examples=[["aci.F0"]]
160
193
  )
161
- csa_exposure_classes: list[CsaExposureClass] | None = pyd.Field(
162
- default=None, description="List of CSA exposure classes", example=["csa.C-2"]
194
+ csa_exposure_classes: list[CsaExposureClass] | None = pydantic.Field(
195
+ default=None, description="List of CSA exposure classes", examples=[["csa.C-2"]]
163
196
  )
164
- en_exposure_classes: list[EnExposureClass] | None = pyd.Field(
165
- default=None, description="List of EN exposure classes", example=["en206.X0"]
197
+ en_exposure_classes: list[EnExposureClass] | None = pydantic.Field(
198
+ default=None, description="List of EN exposure classes", examples=[["en206.X0"]]
199
+ )
200
+ typical_application: ConcreteTypicalApplication | None = pydantic.Field(
201
+ default=None, description="Typical Application"
166
202
  )
167
- typical_application: ConcreteTypicalApplication | None = pyd.Field(default=None, description="Typical Application")
168
203
 
169
204
  # Nested specs:
170
205
  CementGrout: CementGroutV1 | None = None
@@ -174,12 +209,14 @@ class ConcreteV1(BaseOpenEpdHierarchicalSpec):
174
209
  ReadyMix: ReadyMixV1 | None = None
175
210
  Shotcrete: ShotcreteV1 | None = None
176
211
 
177
- _aci_exposure_classes_exclusive_groups_validator = pyd.validator("aci_exposure_classes", allow_reuse=True)(
178
- exclusive_groups_validator_factory(AciExposureClass)
179
- )
180
- _en_exposure_classes_exclusive_groups_validator = pyd.validator("en_exposure_classes", allow_reuse=True)(
181
- exclusive_groups_validator_factory(EnExposureClass)
182
- )
183
- _csa_exposure_classes_exclusive_groups_validator = pyd.validator("csa_exposure_classes", allow_reuse=True)(
184
- exclusive_groups_validator_factory(CsaExposureClass)
185
- )
212
+ @pydantic.field_validator("aci_exposure_classes", mode="before", check_fields=False)
213
+ def _validate_aci_exposure_classes(cls, value):
214
+ return exclusive_groups_validator_factory(AciExposureClass)(cls, value)
215
+
216
+ @pydantic.field_validator("en_exposure_classes", mode="before", check_fields=False)
217
+ def _validate_en_exposure_classes(cls, value):
218
+ return exclusive_groups_validator_factory(EnExposureClass)(cls, value)
219
+
220
+ @pydantic.field_validator("csa_exposure_classes", mode="before", check_fields=False)
221
+ def _validate_csa_exposure_classes(cls, value):
222
+ return exclusive_groups_validator_factory(CsaExposureClass)(cls, value)
@@ -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 openepd.compat.pydantic import pyd
16
+ import pydantic
17
+
17
18
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
18
19
  from openepd.model.specs.enums import ElevatorsBuildingRise, ElevatorsUsageIntensity
19
20
  from openepd.model.validation.quantity import CapacityPerHourStr, LengthMStr, MassKgStr, SpeedStr
@@ -27,21 +28,33 @@ class EscalatorsV1(BaseOpenEpdHierarchicalSpec):
27
28
  which conveys people between the floors of a building.
28
29
  """
29
30
 
30
- vertical_rise: LengthMStr | None = pyd.Field(
31
+ vertical_rise: LengthMStr | None = pydantic.Field(
31
32
  default=None,
32
33
  description="The vertical distance between the top and bottom landings of an escalator",
33
- example="1 m",
34
+ examples=["1 m"],
35
+ )
36
+ speed: SpeedStr | None = pydantic.Field(
37
+ default=None,
38
+ description="Reference speed of the escalator",
39
+ examples=["1 m / s"],
34
40
  )
35
- speed: SpeedStr | None = pyd.Field(default=None, description="Reference speed of the escalator", example="1 m / s")
36
- step_width: LengthMStr | None = pyd.Field(default=None, description="Width of the escalator steps", example="1 m")
37
- max_capacity: CapacityPerHourStr | None = pyd.Field(
38
- default=None, description="Max capacity of escalator in persons per hour", example="1 hour^-1"
41
+ step_width: LengthMStr | None = pydantic.Field(
42
+ default=None, description="Width of the escalator steps", examples=["1 m"]
39
43
  )
40
- indoor: bool | None = pyd.Field(
41
- default=None, description="Escalator can be used for indoor applications", example=True
44
+ max_capacity: CapacityPerHourStr | None = pydantic.Field(
45
+ default=None,
46
+ description="Max capacity of escalator in persons per hour",
47
+ examples=["1 hour^-1"],
42
48
  )
43
- outdoor: bool | None = pyd.Field(
44
- default=None, description="Escalator can be used for outdoor applications", example=True
49
+ indoor: bool | None = pydantic.Field(
50
+ default=None,
51
+ description="Escalator can be used for indoor applications",
52
+ examples=[True],
53
+ )
54
+ outdoor: bool | None = pydantic.Field(
55
+ default=None,
56
+ description="Escalator can be used for outdoor applications",
57
+ examples=[True],
45
58
  )
46
59
 
47
60
  _EXT_VERSION = "1.1"
@@ -53,13 +66,13 @@ class ElevatorsV1(BaseOpenEpdHierarchicalSpec):
53
66
  _EXT_VERSION = "1.0"
54
67
 
55
68
  # Own fields:
56
- usage_intensity: list[ElevatorsUsageIntensity] | None = pyd.Field(
57
- default=None, description="", example=["Very low"]
69
+ usage_intensity: list[ElevatorsUsageIntensity] | None = pydantic.Field(
70
+ default=None, description="", examples=[["Very low"]]
58
71
  )
59
- travel_length: LengthMStr | None = pyd.Field(default=None, description="", example="1 m")
60
- rated_load: MassKgStr | None = pyd.Field(default=None, description="", example="1 kg")
61
- rated_speed: SpeedStr | None = pyd.Field(default=None, description="", example="1 m / s")
62
- building_rise: ElevatorsBuildingRise | None = pyd.Field(default=None, description="", example="Low-rise")
72
+ travel_length: LengthMStr | None = pydantic.Field(default=None, description="", examples=["1 m"])
73
+ rated_load: MassKgStr | None = pydantic.Field(default=None, description="", examples=["1 kg"])
74
+ rated_speed: SpeedStr | None = pydantic.Field(default=None, description="", examples=["1 m / s"])
75
+ building_rise: ElevatorsBuildingRise | None = pydantic.Field(default=None, description="", examples=["Low-rise"])
63
76
 
64
77
 
65
78
  class ConveyingEquipmentV1(BaseOpenEpdHierarchicalSpec):
@@ -15,7 +15,8 @@
15
15
  #
16
16
  from typing import Any, ClassVar
17
17
 
18
- from openepd.compat.pydantic import pyd
18
+ import pydantic
19
+
19
20
  from openepd.model.base import BaseOpenEpdSchema
20
21
 
21
22
 
@@ -48,7 +49,7 @@ def get_safely(d: dict, path: str) -> tuple[bool, Any]:
48
49
  if p not in current:
49
50
  return False, None
50
51
  current = current.get(p)
51
- case pyd.BaseModel() as model:
52
+ case pydantic.BaseModel() as model:
52
53
  if not hasattr(current, p) or p not in model.__fields_set__:
53
54
  return False, None
54
55
  current = getattr(current, p)