openepd 6.13.2__py3-none-any.whl → 7.0.1__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 +0 -6
- 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 +61 -44
- openepd/model/category.py +13 -10
- openepd/model/common.py +107 -59
- 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 +161 -136
- openepd/model/org.py +70 -37
- openepd/model/pcr.py +38 -32
- openepd/model/specs/asphalt.py +31 -22
- openepd/model/specs/base.py +14 -11
- 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 +27 -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 +88 -55
- openepd/model/versioning.py +9 -6
- {openepd-6.13.2.dist-info → openepd-7.0.1.dist-info}/METADATA +2 -2
- openepd-7.0.1.dist-info/RECORD +141 -0
- openepd/compat/__init__.py +0 -15
- openepd/compat/compat_functional_validators.py +0 -25
- openepd/compat/pydantic.py +0 -30
- openepd/patch_pydantic.py +0 -108
- openepd-6.13.2.dist-info/RECORD +0 -145
- {openepd-6.13.2.dist-info → openepd-7.0.1.dist-info}/LICENSE +0 -0
- {openepd-6.13.2.dist-info → openepd-7.0.1.dist-info}/WHEEL +0 -0
@@ -15,30 +15,58 @@
|
|
15
15
|
#
|
16
16
|
from typing import ClassVar, Literal
|
17
17
|
|
18
|
-
|
18
|
+
import pydantic
|
19
|
+
|
19
20
|
from openepd.model.base import BaseOpenEpdSchema
|
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.specs.singular import BaseCompatibilitySpec
|
23
|
-
from openepd.model.validation.numbers import RatioFloat
|
24
24
|
from openepd.model.validation.quantity import LengthInchStr, PressureMPaStr
|
25
25
|
|
26
26
|
|
27
27
|
class ConcreteOptions(BaseOpenEpdSchema):
|
28
28
|
"""Legacy Concrete options model."""
|
29
29
|
|
30
|
-
lightweight: bool | None =
|
31
|
-
default=None,
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
lightweight: bool | None = pydantic.Field(
|
31
|
+
default=None,
|
32
|
+
description="Lightweight. True if < 120lb/ft3 or 1900 kg/m3",
|
33
|
+
examples=[True],
|
34
|
+
)
|
35
|
+
scc: bool | None = pydantic.Field(
|
36
|
+
default=None,
|
37
|
+
description="Self Compacting",
|
38
|
+
examples=[True],
|
39
|
+
)
|
40
|
+
finishable: bool | None = pydantic.Field(
|
41
|
+
default=None,
|
42
|
+
description="Finishable",
|
43
|
+
examples=[True],
|
44
|
+
)
|
45
|
+
air: bool | None = pydantic.Field(
|
46
|
+
default=None,
|
47
|
+
description="Air Entrainment",
|
48
|
+
examples=[True],
|
49
|
+
)
|
50
|
+
co2_entrain: bool | None = pydantic.Field(
|
51
|
+
default=None,
|
52
|
+
description="CO2 Curing. Uses intentionally entrained CO2.",
|
53
|
+
examples=[True],
|
54
|
+
)
|
55
|
+
white_cement: bool | None = pydantic.Field(
|
56
|
+
default=None,
|
57
|
+
description="White Cement",
|
58
|
+
examples=[True],
|
59
|
+
)
|
60
|
+
plc: bool | None = pydantic.Field(
|
61
|
+
default=None,
|
62
|
+
description="Portland Limestone Cement",
|
63
|
+
examples=[True],
|
64
|
+
)
|
65
|
+
fiber_reinforced: bool | None = pydantic.Field(
|
66
|
+
default=None,
|
67
|
+
description="fiber_reinforced",
|
68
|
+
examples=[True],
|
69
|
+
)
|
42
70
|
|
43
71
|
|
44
72
|
class ConcreteOldSpec(BaseCompatibilitySpec):
|
@@ -67,34 +95,41 @@ class ConcreteOldSpec(BaseCompatibilitySpec):
|
|
67
95
|
"concrete.cementitious": "Concrete.cementitious",
|
68
96
|
}
|
69
97
|
|
70
|
-
strength_28d: PressureMPaStr | None =
|
71
|
-
default=None, description="Compressive Strength at 28 days",
|
98
|
+
strength_28d: PressureMPaStr | None = pydantic.Field(
|
99
|
+
default=None, description="Compressive Strength at 28 days", examples=["1 MPa"]
|
72
100
|
)
|
73
|
-
slump: LengthInchStr | None =
|
74
|
-
strength_other: PressureMPaStr | None =
|
101
|
+
slump: LengthInchStr | None = pydantic.Field(default=None, description="Minimum test slump", examples=["2 in"])
|
102
|
+
strength_other: PressureMPaStr | None = pydantic.Field(
|
75
103
|
default=None,
|
76
104
|
description="One additional strength, which can be early (e.g. 3d) or late (e.g. 96d)",
|
77
|
-
|
105
|
+
examples=["30 MPa"],
|
78
106
|
)
|
79
|
-
strength_other_d: Literal[3, 7, 14, 42, 56, 72, 96, 120] | None =
|
107
|
+
strength_other_d: Literal[3, 7, 14, 42, 56, 72, 96, 120] | None = pydantic.Field(
|
80
108
|
default=None,
|
81
109
|
description="Days for the strength field above. Required IF strength_other is provided.",
|
82
|
-
|
110
|
+
examples=[42],
|
83
111
|
)
|
84
|
-
w_c_ratio:
|
85
|
-
default=None, description="Ratio of water to cement",
|
112
|
+
w_c_ratio: float | None = pydantic.Field(
|
113
|
+
default=None, description="Ratio of water to cement", examples=[0.5], ge=0, le=1
|
86
114
|
)
|
87
|
-
aci_exposure_classes: list[AciExposureClass] | None =
|
88
|
-
default=None,
|
115
|
+
aci_exposure_classes: list[AciExposureClass] | None = pydantic.Field(
|
116
|
+
default=None,
|
117
|
+
description="List of ACI318-19 exposure classes this product meets",
|
118
|
+
examples=[["aci.F0"]],
|
89
119
|
)
|
90
|
-
csa_exposure_classes: list[CsaExposureClass] | None =
|
91
|
-
default=None,
|
120
|
+
csa_exposure_classes: list[CsaExposureClass] | None = pydantic.Field(
|
121
|
+
default=None,
|
122
|
+
description="List of CSA A23.1 exposure classes this product meets",
|
123
|
+
examples=[["csa.C-2"]],
|
92
124
|
)
|
93
|
-
en_exposure_classes: list[EnExposureClass] | None =
|
94
|
-
default=None,
|
125
|
+
en_exposure_classes: list[EnExposureClass] | None = pydantic.Field(
|
126
|
+
default=None,
|
127
|
+
description="List of EN206 exposure classes this product meets",
|
128
|
+
examples=[["en206.X0"]],
|
95
129
|
)
|
96
|
-
application: ConcreteTypicalApplication | None =
|
97
|
-
options: ConcreteOptions | None =
|
98
|
-
cementitious: Cementitious | None =
|
99
|
-
default=None,
|
130
|
+
application: ConcreteTypicalApplication | None = pydantic.Field(default=None, description="Typical Application")
|
131
|
+
options: ConcreteOptions | None = pydantic.Field(default=None, description="List of true/false properties")
|
132
|
+
cementitious: Cementitious | None = pydantic.Field(
|
133
|
+
default=None,
|
134
|
+
description="List of cementitious materials, and proportion by mass",
|
100
135
|
)
|
@@ -15,7 +15,8 @@
|
|
15
15
|
#
|
16
16
|
from typing import ClassVar
|
17
17
|
|
18
|
-
|
18
|
+
import pydantic
|
19
|
+
|
19
20
|
from openepd.model.base import BaseOpenEpdSchema
|
20
21
|
from openepd.model.specs.enums import SteelComposition
|
21
22
|
from openepd.model.specs.singular import BaseCompatibilitySpec
|
@@ -27,10 +28,22 @@ from openepd.model.validation.quantity import PressureMPaStr
|
|
27
28
|
class SteelOldOptions(BaseOpenEpdSchema):
|
28
29
|
"""Legacy Steel options model."""
|
29
30
|
|
30
|
-
cold_finished: bool | None =
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
cold_finished: bool | None = pydantic.Field(
|
32
|
+
default=None,
|
33
|
+
description="Cold Finished",
|
34
|
+
examples=[True],
|
35
|
+
)
|
36
|
+
galvanized: bool | None = pydantic.Field(
|
37
|
+
default=None,
|
38
|
+
description="Galvanized",
|
39
|
+
examples=[True],
|
40
|
+
)
|
41
|
+
epoxy: bool | None = pydantic.Field(
|
42
|
+
default=None,
|
43
|
+
description="Epoxy Coated",
|
44
|
+
examples=[True],
|
45
|
+
)
|
46
|
+
steel_fabricated: bool | None = pydantic.Field(default=None, examples=[True], description="Fabricated")
|
34
47
|
|
35
48
|
|
36
49
|
class SteelOldSpec(BaseCompatibilitySpec):
|
@@ -51,25 +64,25 @@ class SteelOldSpec(BaseCompatibilitySpec):
|
|
51
64
|
"steel.options.steel_fabricated": "Steel.RebarSteel.fabricated",
|
52
65
|
# last one is tricky as fabricated might be in multiple cases; thus limited support
|
53
66
|
}
|
54
|
-
form_factor: str | None =
|
55
|
-
steel_composition: SteelComposition | None =
|
67
|
+
form_factor: str | None = pydantic.Field(default=None, description="Product's form factor, read-only.")
|
68
|
+
steel_composition: SteelComposition | None = pydantic.Field(
|
56
69
|
default=None,
|
57
70
|
description="Basic chemical composition. Generally the ASTM or EN grade is a subcategory of one of these.",
|
58
|
-
|
71
|
+
examples=["Carbon"],
|
59
72
|
)
|
60
|
-
Fy: PressureMPaStr | None =
|
73
|
+
Fy: PressureMPaStr | None = pydantic.Field(
|
61
74
|
default=None,
|
62
75
|
description="Minimum Yield Strength",
|
63
|
-
|
76
|
+
examples=["2000 psi"],
|
64
77
|
)
|
65
|
-
making_route: SteelMakingRoute | None =
|
78
|
+
making_route: SteelMakingRoute | None = pydantic.Field(
|
66
79
|
default=None, description="List of true/false properties for steelmaking route"
|
67
80
|
)
|
68
|
-
ASTM: list[Standard] | None =
|
81
|
+
ASTM: list[Standard] | None = pydantic.Field(
|
69
82
|
default=None, description="ASTM standard(s) to which this product complies."
|
70
83
|
)
|
71
|
-
SAE: list[Standard] | None =
|
84
|
+
SAE: list[Standard] | None = pydantic.Field(
|
72
85
|
default=None, description="AISA/SAE standard(s) to which this product complies."
|
73
86
|
)
|
74
|
-
EN: list[Standard] | None =
|
75
|
-
options: SteelOldOptions | None =
|
87
|
+
EN: list[Standard] | None = pydantic.Field(default=None, description="EN 10027 number(s).")
|
88
|
+
options: SteelOldOptions | None = pydantic.Field(default=None, description="List of true/false properties")
|
@@ -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 CableTraysMaterial, EnergySource, RacewaysMaterial
|
19
20
|
from openepd.model.specs.singular.mixins.conduit_mixin import ConduitMixin
|
@@ -61,14 +62,18 @@ class CableTraysV1(BaseOpenEpdHierarchicalSpec):
|
|
61
62
|
_EXT_VERSION = "1.0"
|
62
63
|
|
63
64
|
# Own fields:
|
64
|
-
height: LengthMmStr | None =
|
65
|
-
width: LengthMmStr | None =
|
66
|
-
depth: LengthMmStr | None =
|
67
|
-
static_load: MassKgStr | None =
|
68
|
-
ventilated: bool | None =
|
69
|
-
default=None,
|
65
|
+
height: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["100 mm"])
|
66
|
+
width: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["100 mm"])
|
67
|
+
depth: LengthMmStr | None = pydantic.Field(default=None, description="", examples=["100 mm"])
|
68
|
+
static_load: MassKgStr | None = pydantic.Field(default=None, description="", examples=["1 kg"])
|
69
|
+
ventilated: bool | None = pydantic.Field(
|
70
|
+
default=None,
|
71
|
+
description="At least 40% of the tray base is open to air flow",
|
72
|
+
examples=[True],
|
73
|
+
)
|
74
|
+
cable_trays_material: CableTraysMaterial | None = pydantic.Field(
|
75
|
+
default=None, description="", examples=["Stainless Steel"]
|
70
76
|
)
|
71
|
-
cable_trays_material: CableTraysMaterial | None = pyd.Field(default=None, description="", example="Stainless Steel")
|
72
77
|
|
73
78
|
|
74
79
|
class ElectricalBusesV1(BaseOpenEpdHierarchicalSpec):
|
@@ -104,11 +109,19 @@ class RacewaysV1(BaseOpenEpdHierarchicalSpec):
|
|
104
109
|
_EXT_VERSION = "1.0"
|
105
110
|
|
106
111
|
# Own fields:
|
107
|
-
width: LengthMStr | None =
|
108
|
-
depth: LengthMStr | None =
|
109
|
-
painted: bool | None =
|
110
|
-
|
111
|
-
|
112
|
+
width: LengthMStr | None = pydantic.Field(default=None, description="", examples=["100 mm"])
|
113
|
+
depth: LengthMStr | None = pydantic.Field(default=None, description="", examples=["100 mm"])
|
114
|
+
painted: bool | None = pydantic.Field(
|
115
|
+
default=None,
|
116
|
+
description="",
|
117
|
+
examples=[True],
|
118
|
+
)
|
119
|
+
divided: bool | None = pydantic.Field(
|
120
|
+
default=None,
|
121
|
+
description="",
|
122
|
+
examples=[True],
|
123
|
+
)
|
124
|
+
raceways_material: RacewaysMaterial | None = pydantic.Field(default=None, description="", examples=["Aluminum"])
|
112
125
|
|
113
126
|
|
114
127
|
class FueledElectricalGeneratorsV1(BaseOpenEpdHierarchicalSpec):
|
@@ -147,7 +160,7 @@ class ElectricityFromSpecificGeneratorV1(BaseOpenEpdHierarchicalSpec):
|
|
147
160
|
_EXT_VERSION = "1.0"
|
148
161
|
|
149
162
|
# Own fields:
|
150
|
-
energy_source: EnergySource | None =
|
163
|
+
energy_source: EnergySource | None = pydantic.Field(default=None, description="", examples=["Grid"])
|
151
164
|
|
152
165
|
|
153
166
|
class PowerPurchaseAgreementsV1(BaseOpenEpdHierarchicalSpec):
|
@@ -160,7 +173,7 @@ class PowerPurchaseAgreementsV1(BaseOpenEpdHierarchicalSpec):
|
|
160
173
|
_EXT_VERSION = "1.0"
|
161
174
|
|
162
175
|
# Own fields:
|
163
|
-
energy_source: EnergySource | None =
|
176
|
+
energy_source: EnergySource | None = pydantic.Field(default=None, description="", examples=["Grid"])
|
164
177
|
|
165
178
|
|
166
179
|
class LightbulbsV1(BaseOpenEpdHierarchicalSpec):
|
@@ -255,33 +268,48 @@ class LightingV1(BaseOpenEpdHierarchicalSpec):
|
|
255
268
|
_EXT_VERSION = "1.0"
|
256
269
|
|
257
270
|
# Own fields:
|
258
|
-
color_temperature: ColorTemperatureStr | None =
|
259
|
-
typical_utilization: UtilizationStr | None =
|
260
|
-
luminosity: LuminosityStr | None =
|
261
|
-
wattage: PowerStr | None =
|
262
|
-
color_rendering_index: float | None =
|
263
|
-
dimmable: bool | None =
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
)
|
268
|
-
_color_temperature_quantity_le_validator = pyd.validator("color_temperature", allow_reuse=True)(
|
269
|
-
validate_quantity_le_factory("1E+04 K")
|
270
|
-
)
|
271
|
-
_typical_utilization_unit_validator = pyd.validator("typical_utilization", allow_reuse=True)(
|
272
|
-
validate_quantity_unit_factory("h / yr")
|
273
|
-
)
|
274
|
-
_typical_utilization_quantity_ge_validator = pyd.validator("typical_utilization", allow_reuse=True)(
|
275
|
-
validate_quantity_ge_factory("25 h / yr")
|
276
|
-
)
|
277
|
-
_luminosity_quantity_ge_validator = pyd.validator("luminosity", allow_reuse=True)(
|
278
|
-
validate_quantity_ge_factory("450 lumen")
|
279
|
-
)
|
280
|
-
_luminosity_quantity_le_validator = pyd.validator("luminosity", allow_reuse=True)(
|
281
|
-
validate_quantity_le_factory("2.6E+03 lumen")
|
271
|
+
color_temperature: ColorTemperatureStr | None = pydantic.Field(default=None, description="", examples=["1 K"])
|
272
|
+
typical_utilization: UtilizationStr | None = pydantic.Field(default=None, description="", examples=["1 h / yr"])
|
273
|
+
luminosity: LuminosityStr | None = pydantic.Field(default=None, description="", examples=["1 lumen"])
|
274
|
+
wattage: PowerStr | None = pydantic.Field(default=None, description="")
|
275
|
+
color_rendering_index: float | None = pydantic.Field(default=None, description="", examples=[2.3])
|
276
|
+
dimmable: bool | None = pydantic.Field(
|
277
|
+
default=None,
|
278
|
+
description="",
|
279
|
+
examples=[True],
|
282
280
|
)
|
283
|
-
|
284
|
-
|
281
|
+
|
282
|
+
@pydantic.field_validator("color_temperature")
|
283
|
+
def _color_temperature_quantity_ge_validator(cls, value):
|
284
|
+
return validate_quantity_ge_factory("1E+03 K")(cls, value)
|
285
|
+
|
286
|
+
@pydantic.field_validator("color_temperature")
|
287
|
+
def _color_temperature_quantity_le_validator(cls, value):
|
288
|
+
return validate_quantity_le_factory("1E+04 K")(cls, value)
|
289
|
+
|
290
|
+
@pydantic.field_validator("typical_utilization")
|
291
|
+
def _typical_utilization_unit_validator(cls, value):
|
292
|
+
return validate_quantity_unit_factory("h / yr")(cls, value)
|
293
|
+
|
294
|
+
@pydantic.field_validator("typical_utilization")
|
295
|
+
def _typical_utilization_quantity_ge_validator(cls, value):
|
296
|
+
return validate_quantity_ge_factory("25 h / yr")(cls, value)
|
297
|
+
|
298
|
+
@pydantic.field_validator("luminosity")
|
299
|
+
def _luminosity_quantity_ge_validator(cls, value):
|
300
|
+
return validate_quantity_ge_factory("450 lumen")(cls, value)
|
301
|
+
|
302
|
+
@pydantic.field_validator("luminosity")
|
303
|
+
def _luminosity_quantity_le_validator(cls, value):
|
304
|
+
return validate_quantity_le_factory("2.6E+03 lumen")(cls, value)
|
305
|
+
|
306
|
+
@pydantic.field_validator("wattage")
|
307
|
+
def _wattage_quantity_ge_validator(cls, value):
|
308
|
+
return validate_quantity_ge_factory("5 W")(cls, value)
|
309
|
+
|
310
|
+
@pydantic.field_validator("wattage")
|
311
|
+
def _wattage_quantity_le_validator(cls, value):
|
312
|
+
return validate_quantity_le_factory("100 W")(cls, value)
|
285
313
|
|
286
314
|
# Nested specs:
|
287
315
|
Lightbulbs: LightbulbsV1 | None = None
|