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.
- 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/m49/__init__.py +2 -0
- openepd/m49/const.py +5 -2
- openepd/m49/{geo_converter.py → utils.py} +24 -2
- 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.1.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.1.dist-info/RECORD +0 -145
- {openepd-6.13.1.dist-info → openepd-7.0.0.dist-info}/LICENSE +0 -0
- {openepd-6.13.1.dist-info → openepd-7.0.0.dist-info}/WHEEL +0 -0
openepd/model/org.py
CHANGED
@@ -13,11 +13,12 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
-
from typing import Annotated, Optional
|
16
|
+
from typing import Annotated, List, Optional
|
17
17
|
|
18
18
|
from openlocationcode import openlocationcode
|
19
|
+
import pydantic
|
20
|
+
from pydantic import ConfigDict, Field, StringConstraints
|
19
21
|
|
20
|
-
from openepd.compat.pydantic import pyd
|
21
22
|
from openepd.model.base import BaseOpenEpdSchema
|
22
23
|
from openepd.model.common import Location, WithAltIdsMixin, WithAttachmentsMixin
|
23
24
|
from openepd.model.validation.common import ReferenceStr
|
@@ -26,18 +27,19 @@ from openepd.model.validation.common import ReferenceStr
|
|
26
27
|
class OrgRef(BaseOpenEpdSchema):
|
27
28
|
"""Represents Organisation with minimal data."""
|
28
29
|
|
29
|
-
web_domain: str | None =
|
30
|
-
description="A web domain owned by organization. Typically is the org's home website address",
|
30
|
+
web_domain: str | None = pydantic.Field(
|
31
|
+
description="A web domain owned by organization. Typically is the org's home website address",
|
32
|
+
default=None,
|
31
33
|
)
|
32
|
-
name: str | None =
|
34
|
+
name: str | None = pydantic.Field(
|
33
35
|
max_length=200,
|
34
36
|
description="Common name for organization",
|
35
|
-
|
37
|
+
examples=["C Change Labs"],
|
36
38
|
default=None,
|
37
39
|
)
|
38
|
-
ref: ReferenceStr | None =
|
40
|
+
ref: ReferenceStr | None = pydantic.Field(
|
39
41
|
default=None,
|
40
|
-
|
42
|
+
examples=["https://openepd.buildingtransparency.org/api/orgs/c-change-labs.com"],
|
41
43
|
description="Reference to this Org's JSON object",
|
42
44
|
)
|
43
45
|
|
@@ -45,19 +47,37 @@ class OrgRef(BaseOpenEpdSchema):
|
|
45
47
|
class Org(WithAttachmentsMixin, WithAltIdsMixin, OrgRef):
|
46
48
|
"""Represent an organization."""
|
47
49
|
|
48
|
-
alt_names:
|
50
|
+
alt_names: (
|
51
|
+
Annotated[
|
52
|
+
list[str],
|
53
|
+
Annotated[
|
54
|
+
List[Annotated[str, StringConstraints(max_length=200)]],
|
55
|
+
Field(max_length=255),
|
56
|
+
],
|
57
|
+
]
|
58
|
+
| None
|
59
|
+
) = pydantic.Field(
|
49
60
|
description="List of other names for organization",
|
50
|
-
|
61
|
+
examples=[["C-Change Labs", "C-Change Labs inc."]],
|
51
62
|
default=None,
|
52
63
|
)
|
53
64
|
# TODO: NEW field, not in the spec
|
54
65
|
|
55
|
-
owner: Optional["OrgRef"] =
|
56
|
-
subsidiaries:
|
66
|
+
owner: Optional["OrgRef"] = pydantic.Field(description="Organization that controls this organization", default=None)
|
67
|
+
subsidiaries: (
|
68
|
+
Annotated[
|
69
|
+
list["OrgRef"],
|
70
|
+
Annotated[
|
71
|
+
List[Annotated[str, StringConstraints(max_length=200)]],
|
72
|
+
Field(max_length=255),
|
73
|
+
],
|
74
|
+
]
|
75
|
+
| None
|
76
|
+
) = pydantic.Field(
|
57
77
|
description="Organizations controlled by this organization",
|
58
78
|
default=None,
|
59
79
|
)
|
60
|
-
hq_location: Location | None =
|
80
|
+
hq_location: Location | None = pydantic.Field(
|
61
81
|
default=None,
|
62
82
|
description="Location of a place of business, preferably the corporate headquarters.",
|
63
83
|
)
|
@@ -66,21 +86,21 @@ class Org(WithAttachmentsMixin, WithAltIdsMixin, OrgRef):
|
|
66
86
|
class PlantRef(BaseOpenEpdSchema):
|
67
87
|
"""Represents Plant with minimal data."""
|
68
88
|
|
69
|
-
id: str | None =
|
89
|
+
id: str | None = pydantic.Field(
|
70
90
|
description="Plus code (aka Open Location Code) of plant's location and "
|
71
91
|
"owner's web domain joined with `.`(dot).",
|
72
|
-
|
92
|
+
examples=["865P2W3V+3W.interface.com"],
|
73
93
|
default=None,
|
74
94
|
)
|
75
|
-
name: str | None =
|
95
|
+
name: str | None = pydantic.Field(
|
76
96
|
max_length=200,
|
77
97
|
description="Manufacturer's name for plant. Recommended < 40 chars",
|
78
|
-
|
98
|
+
examples=["Dalton, GA"],
|
79
99
|
default=None,
|
80
100
|
)
|
81
|
-
ref: ReferenceStr | None =
|
101
|
+
ref: ReferenceStr | None = pydantic.Field(
|
82
102
|
default=None,
|
83
|
-
|
103
|
+
examples=["https://openepd.buildingtransparency.org/api/orgs/c-change-labs.com"],
|
84
104
|
description="Reference to this Plant's JSON object",
|
85
105
|
)
|
86
106
|
|
@@ -88,36 +108,38 @@ class PlantRef(BaseOpenEpdSchema):
|
|
88
108
|
class Plant(PlantRef, WithAttachmentsMixin, WithAltIdsMixin):
|
89
109
|
"""Represent a manufacturing plant."""
|
90
110
|
|
91
|
-
pluscode: str | None =
|
111
|
+
pluscode: str | None = pydantic.Field(
|
92
112
|
default=None,
|
93
113
|
description="(deprecated) Plus code (aka Open Location Code) of plant's location",
|
94
114
|
deprecated="Pluscode field is deprecated. If users need a pluscode they can obtain it from "
|
95
115
|
"`id` like this: `id.spit('.', maxsplit=1)[0]`",
|
96
116
|
)
|
97
|
-
latitude: float | None =
|
98
|
-
default=None,
|
117
|
+
latitude: float | None = pydantic.Field(
|
118
|
+
default=None,
|
119
|
+
description="(deprecated) Latitude of the plant location. Use 'location' fields instead.",
|
99
120
|
)
|
100
|
-
longitude: float | None =
|
101
|
-
default=None,
|
121
|
+
longitude: float | None = pydantic.Field(
|
122
|
+
default=None,
|
123
|
+
description="(deprecated) Longitude of the plant location. Use 'location' fields instead.",
|
102
124
|
)
|
103
|
-
owner: Org | None =
|
104
|
-
address: str | None =
|
125
|
+
owner: Org | None = pydantic.Field(description="Organization that owns the plant", default=None)
|
126
|
+
address: str | None = pydantic.Field(
|
105
127
|
max_length=200,
|
106
128
|
default=None,
|
107
129
|
description="(deprecated) Text address, preferably geocoded. Use 'location' fields instead",
|
108
|
-
|
130
|
+
examples=["1503 Orchard Hill Rd, LaGrange, GA 30240, United States"],
|
109
131
|
)
|
110
|
-
contact_email:
|
111
|
-
description="Email contact",
|
132
|
+
contact_email: pydantic.EmailStr | None = pydantic.Field(
|
133
|
+
description="Email contact", examples=["info@interface.com"], default=None
|
112
134
|
)
|
113
|
-
location: Location | None =
|
135
|
+
location: Location | None = pydantic.Field(description="Location of the plant", default=None)
|
114
136
|
|
115
137
|
@classmethod
|
116
138
|
def get_asset_type(cls) -> str | None:
|
117
139
|
"""Return the asset type of this class (see BaseOpenEpdSchema.get_asset_type for details)."""
|
118
140
|
return "org"
|
119
141
|
|
120
|
-
@
|
142
|
+
@pydantic.field_validator("id")
|
121
143
|
def _validate_id(cls, v: str) -> str:
|
122
144
|
if not v:
|
123
145
|
return v
|
@@ -133,5 +155,4 @@ class Plant(PlantRef, WithAttachmentsMixin, WithAltIdsMixin):
|
|
133
155
|
raise ValueError("Incorrect web_domain for plant")
|
134
156
|
return v
|
135
157
|
|
136
|
-
|
137
|
-
allow_population_by_field_name = True
|
158
|
+
model_config = ConfigDict(populate_by_name=True)
|
openepd/model/pcr.py
CHANGED
@@ -17,7 +17,8 @@ import datetime
|
|
17
17
|
from enum import StrEnum
|
18
18
|
from typing import Annotated, Optional
|
19
19
|
|
20
|
-
|
20
|
+
import pydantic
|
21
|
+
|
21
22
|
from openepd.model.base import BaseOpenEpdSchema, OpenXpdUUID
|
22
23
|
from openepd.model.common import Amount, WithAltIdsMixin, WithAttachmentsMixin
|
23
24
|
from openepd.model.org import Org
|
@@ -36,87 +37,92 @@ class PcrStatus(StrEnum):
|
|
36
37
|
class PcrRef(BaseOpenEpdSchema):
|
37
38
|
"""Reference to a PCR."""
|
38
39
|
|
39
|
-
id: OpenXpdUUID | None =
|
40
|
+
id: OpenXpdUUID | None = pydantic.Field(
|
40
41
|
description="The unique ID for this PCR. To ensure global uniqueness, should be registered "
|
41
42
|
"at open-xpd-uuid.cqd.io/register or a coordinating registry.",
|
42
|
-
|
43
|
+
examples=["ec3xpgq2"],
|
43
44
|
default=None,
|
44
45
|
)
|
45
|
-
name: str | None =
|
46
|
+
name: str | None = pydantic.Field(
|
46
47
|
max_length=200,
|
47
48
|
description="Full document name as listed in source document",
|
48
|
-
|
49
|
+
examples=["c-PCR-003 Concrete and concrete elements (EN 16757)"],
|
49
50
|
)
|
50
|
-
ref:
|
51
|
+
ref: pydantic.AnyUrl | None = pydantic.Field(
|
51
52
|
description="Reference to this PCR's JSON object",
|
52
|
-
|
53
|
+
examples=["https://openepd.buildingtransparency.org/api/pcrs/1u7zsed8"],
|
53
54
|
)
|
54
55
|
|
55
56
|
|
56
57
|
class Pcr(WithAttachmentsMixin, WithAltIdsMixin, BaseOpenEpdSchema):
|
57
58
|
"""Represent a PCR (Product Category Rules)."""
|
58
59
|
|
59
|
-
id: OpenXpdUUID | None =
|
60
|
+
id: OpenXpdUUID | None = pydantic.Field(
|
60
61
|
description="The unique ID for this PCR. To ensure global uniqueness, should be registered "
|
61
62
|
"at open-xpd-uuid.cqd.io/register or a coordinating registry.",
|
62
|
-
|
63
|
+
examples=["ec3xpgq2"],
|
63
64
|
default=None,
|
64
65
|
)
|
65
|
-
issuer: Org | None =
|
66
|
-
issuer_doc_id: str | None =
|
66
|
+
issuer: Org | None = pydantic.Field(description="Organization issuing this PCR", default=None)
|
67
|
+
issuer_doc_id: str | None = pydantic.Field(
|
67
68
|
max_length=40,
|
68
69
|
default=None,
|
69
70
|
description="Document ID or code created by issuer",
|
70
|
-
|
71
|
+
examples=["c-PCR-003"],
|
71
72
|
)
|
72
|
-
name: str | None =
|
73
|
+
name: str | None = pydantic.Field(
|
73
74
|
max_length=200,
|
74
75
|
default=None,
|
75
76
|
description="Full document name as listed in source document",
|
76
|
-
|
77
|
+
examples=["c-PCR-003 Concrete and concrete elements (EN 16757)"],
|
77
78
|
)
|
78
|
-
short_name: str | None =
|
79
|
+
short_name: str | None = pydantic.Field(
|
79
80
|
default=None,
|
80
81
|
description="A shortened name without boilerplate text.",
|
81
|
-
|
82
|
+
examples=["Concrete and Concrete Elements"],
|
82
83
|
)
|
83
|
-
declared_units: list[Amount] | None =
|
84
|
+
declared_units: list[Amount] | None = pydantic.Field(
|
84
85
|
description="SI declared units for this PCR. If a functional unit is "
|
85
86
|
"utilized, the declared unit shall refer to the amount of "
|
86
|
-
"product associated with the A1-A3 life cycle stage."
|
87
|
+
"product associated with the A1-A3 life cycle stage.",
|
88
|
+
default=None,
|
87
89
|
)
|
88
|
-
version: str | None =
|
90
|
+
version: str | None = pydantic.Field(
|
89
91
|
description="Document version, as expressed in document.",
|
90
|
-
|
92
|
+
examples=["1.0.2"],
|
91
93
|
default=None,
|
92
94
|
)
|
93
|
-
date_of_issue: datetime.datetime | None =
|
94
|
-
|
95
|
+
date_of_issue: datetime.datetime | None = pydantic.Field(
|
96
|
+
examples=[datetime.datetime(day=11, month=9, year=2019, tzinfo=datetime.timezone.utc)],
|
95
97
|
default=None,
|
96
98
|
description="First day on which the document is valid",
|
97
99
|
)
|
98
|
-
valid_until: datetime.datetime | None =
|
99
|
-
|
100
|
+
valid_until: datetime.datetime | None = pydantic.Field(
|
101
|
+
examples=[datetime.datetime(day=11, month=9, year=2019, tzinfo=datetime.timezone.utc)],
|
100
102
|
default=None,
|
101
103
|
description="Last day on which the document is valid",
|
102
104
|
)
|
103
|
-
doc: str | None =
|
104
|
-
|
105
|
+
doc: str | None = pydantic.Field(
|
106
|
+
default=None,
|
107
|
+
description="URL to original document, preferably directly to a PDF.",
|
108
|
+
)
|
109
|
+
parent: Optional["Pcr"] = pydantic.Field(
|
105
110
|
description="The parent PCR, base PCR, `Part A` PCR",
|
106
111
|
default=None,
|
107
112
|
)
|
108
|
-
status: PcrStatus | None =
|
113
|
+
status: PcrStatus | None = pydantic.Field(
|
109
114
|
default=None,
|
110
115
|
description="The current release status of this PCR. "
|
111
116
|
"A PCR with valid_until in the past must have status Expired or Sunset; a PCR with valid_until "
|
112
117
|
"more than 5 years in the past must have status Sunset. Compliant systems should automatically "
|
113
118
|
"update these fields within 24 hours.",
|
114
119
|
)
|
115
|
-
product_classes: dict[str, str | list[str]] =
|
116
|
-
description="List of classifications, including Masterformat and UNSPC",
|
120
|
+
product_classes: dict[str, str | list[str]] = pydantic.Field(
|
121
|
+
description="List of classifications, including Masterformat and UNSPC",
|
122
|
+
default_factory=dict,
|
117
123
|
)
|
118
|
-
applicable_in: list[Annotated[str,
|
119
|
-
|
124
|
+
applicable_in: list[Annotated[str, pydantic.Field(min_length=2, max_length=2)]] | None = pydantic.Field(
|
125
|
+
max_length=100,
|
120
126
|
default=None,
|
121
127
|
description="Jurisdiction(s) in which EPD is applicable. An empty array, or absent properties, "
|
122
128
|
"implies global applicability. Accepts "
|
@@ -124,7 +130,7 @@ class Pcr(WithAttachmentsMixin, WithAltIdsMixin, BaseOpenEpdSchema):
|
|
124
130
|
"[M49 region codes](https://unstats.un.org/unsd/methodology/m49/), "
|
125
131
|
'or the alias "EU27" for the 27 members of the Euro bloc, or the alias "NAFTA" '
|
126
132
|
"for the members of North American Free Trade Agreement",
|
127
|
-
|
133
|
+
examples=[["US", "CA", "MX", "EU27", "NAFTA"]],
|
128
134
|
)
|
129
135
|
|
130
136
|
@classmethod
|
openepd/model/specs/asphalt.py
CHANGED
@@ -15,10 +15,10 @@
|
|
15
15
|
#
|
16
16
|
from enum import StrEnum
|
17
17
|
|
18
|
-
|
18
|
+
import pydantic
|
19
|
+
|
19
20
|
from openepd.model.common import OpenEPDUnit
|
20
21
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
|
21
|
-
from openepd.model.validation.numbers import RatioFloat
|
22
22
|
from openepd.model.validation.quantity import LengthMmStr, TemperatureCStr, validate_quantity_unit_factory
|
23
23
|
|
24
24
|
|
@@ -45,42 +45,51 @@ class AsphaltV1(BaseOpenEpdHierarchicalSpec):
|
|
45
45
|
|
46
46
|
_EXT_VERSION = "1.1"
|
47
47
|
|
48
|
-
asphalt_aggregate_size_max: LengthMmStr | None =
|
49
|
-
default=None,
|
48
|
+
asphalt_aggregate_size_max: LengthMmStr | None = pydantic.Field(
|
49
|
+
default=None, examples=["5mm"], description="Max aggregate size"
|
50
50
|
)
|
51
51
|
|
52
|
-
asphalt_rap:
|
53
|
-
default=None,
|
52
|
+
asphalt_rap: float | None = pydantic.Field(
|
53
|
+
default=None,
|
54
|
+
description="Percent of mixture that has been replaced by recycled " "asphalt pavement (RAP).",
|
55
|
+
ge=0,
|
56
|
+
le=1,
|
54
57
|
)
|
55
|
-
asphalt_ras:
|
56
|
-
default=None,
|
58
|
+
asphalt_ras: float | None = pydantic.Field(
|
59
|
+
default=None,
|
60
|
+
description="Percent of mixture that has been replaced by recycled " "asphalt shingles (RAS).",
|
61
|
+
ge=0,
|
62
|
+
le=1,
|
57
63
|
)
|
58
|
-
asphalt_ground_tire_rubber:
|
59
|
-
default=None,
|
64
|
+
asphalt_ground_tire_rubber: float | None = pydantic.Field(
|
65
|
+
default=None,
|
66
|
+
description="Percent of mixture that has been replaced " "by ground tire rubber (GTR).",
|
67
|
+
ge=0,
|
68
|
+
le=1,
|
60
69
|
)
|
61
70
|
|
62
|
-
asphalt_max_temperature: TemperatureCStr | None =
|
71
|
+
asphalt_max_temperature: TemperatureCStr | None = pydantic.Field(
|
63
72
|
default=None,
|
64
73
|
description="The upper threshold temperature to which an asphalt "
|
65
74
|
"binder can be heated preventing the asphalt mixture "
|
66
75
|
"from rutting",
|
67
76
|
)
|
68
|
-
asphalt_min_temperature: TemperatureCStr | None =
|
77
|
+
asphalt_min_temperature: TemperatureCStr | None = pydantic.Field(
|
69
78
|
default=None,
|
70
79
|
description="The lower threshold temperature for an asphalt "
|
71
80
|
"binder to prevent thermal cracking of the asphalt"
|
72
81
|
" mixture.",
|
73
82
|
)
|
74
83
|
|
75
|
-
asphalt_mix_type: AsphaltMixType | None =
|
76
|
-
asphalt_gradation: AsphaltGradation | None =
|
84
|
+
asphalt_mix_type: AsphaltMixType | None = pydantic.Field(default=None, description="Asphalt mix type")
|
85
|
+
asphalt_gradation: AsphaltGradation | None = pydantic.Field(default=None, description="Asphalt gradation")
|
77
86
|
|
78
|
-
asphalt_sbr: bool | None =
|
79
|
-
asphalt_sbs: bool | None =
|
80
|
-
asphalt_ppa: bool | None =
|
81
|
-
asphalt_gtr: bool | None =
|
82
|
-
asphalt_pmb: bool | None =
|
87
|
+
asphalt_sbr: bool | None = pydantic.Field(default=None, description="Styrene-butadiene rubber (SBR)")
|
88
|
+
asphalt_sbs: bool | None = pydantic.Field(default=None, description="Styrene-butadiene-styrene (SBS)")
|
89
|
+
asphalt_ppa: bool | None = pydantic.Field(default=None, description="Polyphosphoric acid (PPA)")
|
90
|
+
asphalt_gtr: bool | None = pydantic.Field(default=None, description="Ground tire rubber (GTR)")
|
91
|
+
asphalt_pmb: bool | None = pydantic.Field(default=None, description="Polymer modified bitumen (PMB)")
|
83
92
|
|
84
|
-
|
85
|
-
|
86
|
-
|
93
|
+
@pydantic.field_validator("asphalt_aggregate_size_max", mode="before")
|
94
|
+
def _aggregate_size_max_validator(cls, value):
|
95
|
+
return validate_quantity_unit_factory(OpenEPDUnit.m)(cls, value)
|
openepd/model/specs/base.py
CHANGED
@@ -17,7 +17,9 @@ import dataclasses
|
|
17
17
|
from types import UnionType
|
18
18
|
from typing import Any
|
19
19
|
|
20
|
-
|
20
|
+
import pydantic
|
21
|
+
from pydantic import ConfigDict
|
22
|
+
|
21
23
|
from openepd.model.base import BaseOpenEpdSchema, Version
|
22
24
|
from openepd.model.validation.common import validate_version_compatibility, validate_version_format
|
23
25
|
from openepd.model.validation.quantity import ExternalValidationConfig, QuantityValidator
|
@@ -27,8 +29,7 @@ from openepd.model.versioning import WithExtVersionMixin
|
|
27
29
|
class BaseOpenEpdSpec(BaseOpenEpdSchema):
|
28
30
|
"""Base class for all OpenEPD specs."""
|
29
31
|
|
30
|
-
|
31
|
-
use_enum_values = False # we need to store enums as strings and not values
|
32
|
+
model_config = ConfigDict(use_enum_values=False)
|
32
33
|
|
33
34
|
|
34
35
|
class BaseOpenEpdHierarchicalSpec(BaseOpenEpdSpec, WithExtVersionMixin):
|
@@ -42,12 +43,13 @@ class BaseOpenEpdHierarchicalSpec(BaseOpenEpdSpec, WithExtVersionMixin):
|
|
42
43
|
Version.parse_version(self._EXT_VERSION) # validate format correctness
|
43
44
|
super().__init__(**{"ext_version": self._EXT_VERSION, **data})
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
)
|
46
|
+
@pydantic.field_validator("ext_version", mode="before")
|
47
|
+
def _version_format_validator(cls, v: str) -> str:
|
48
|
+
return validate_version_format(v)
|
49
|
+
|
50
|
+
@pydantic.field_validator("ext_version", mode="before")
|
51
|
+
def _version_major_match_validator(cls, v: str) -> str:
|
52
|
+
return validate_version_compatibility("_EXT_VERSION")(cls, v) # type: ignore[arg-type]
|
51
53
|
|
52
54
|
|
53
55
|
def setup_external_validators(quantity_validator: QuantityValidator):
|
openepd/model/specs/concrete.py
CHANGED
@@ -13,98 +13,119 @@
|
|
13
13
|
# See the License for the specific language governing permissions and
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
|
+
import pydantic
|
16
17
|
|
17
|
-
from openepd.compat.pydantic import pyd
|
18
18
|
from openepd.model.base import BaseOpenEpdSchema
|
19
19
|
from openepd.model.specs.base import BaseOpenEpdSpec
|
20
|
-
from openepd.model.validation.numbers import RatioFloat
|
21
20
|
|
22
21
|
|
23
22
|
class ConcreteTypicalApplication(BaseOpenEpdSpec):
|
24
23
|
"""Typical Application for Concrete."""
|
25
24
|
|
26
|
-
fnd: bool | None =
|
25
|
+
fnd: bool | None = pydantic.Field(
|
27
26
|
description="Foundation. Typically used in direct contact with soil, e.g. footings, piles, mass concrete, "
|
28
27
|
"mat foundations, and similar applications.",
|
29
|
-
|
28
|
+
examples=[True],
|
30
29
|
default=None,
|
31
30
|
)
|
32
|
-
sog: bool | None =
|
31
|
+
sog: bool | None = pydantic.Field(
|
33
32
|
description="Slab on Grade. Typically used in continuously supported horizontal "
|
34
33
|
"applications e.g. slab on grade, topping slabs, sidewalks, and roadways.",
|
35
|
-
|
34
|
+
examples=[True],
|
36
35
|
default=None,
|
37
36
|
)
|
38
|
-
hrz: bool | None =
|
37
|
+
hrz: bool | None = pydantic.Field(
|
39
38
|
description="Elevated Horizontal. Typically used in elevated horizontal applications, either on metal deck or "
|
40
39
|
"where soffit formwork must be removed, e.g. post-tension plates, rebar plates, beams and slabs, "
|
41
40
|
"waffle slabs.",
|
42
|
-
|
41
|
+
examples=[True],
|
43
42
|
default=None,
|
44
43
|
)
|
45
|
-
vrt_wall: bool | None =
|
46
|
-
vrt_column: bool | None =
|
47
|
-
vrt_other: bool | None =
|
44
|
+
vrt_wall: bool | None = pydantic.Field(description="Vertical Wall.", examples=[True], default=None)
|
45
|
+
vrt_column: bool | None = pydantic.Field(description="Vertical Column.", examples=[True], default=None)
|
46
|
+
vrt_other: bool | None = pydantic.Field(
|
48
47
|
description="Vertical Other. Typically used in vertical applications other than "
|
49
48
|
"walls or columns, e.g. sloped surfaces where formwork is required "
|
50
49
|
"on multiple faces.",
|
51
|
-
|
50
|
+
examples=[True],
|
52
51
|
default=None,
|
53
52
|
)
|
54
|
-
sht: bool | None =
|
55
|
-
description="Shotcrete. Pneumatically applied, without formwork on all sides.",
|
53
|
+
sht: bool | None = pydantic.Field(
|
54
|
+
description="Shotcrete. Pneumatically applied, without formwork on all sides.",
|
55
|
+
examples=[True],
|
56
|
+
default=None,
|
56
57
|
)
|
57
|
-
cdf: bool | None =
|
58
|
+
cdf: bool | None = pydantic.Field(
|
58
59
|
description="Flowable Fill (CDF). Typically used to fill voids, backfill retaining "
|
59
60
|
"walls, as a sub-base, and similar applications. Also called Controlled "
|
60
61
|
"Density Fill (CDF) or Controlled Low Strength Materials (CLSM).",
|
61
|
-
|
62
|
+
examples=[True],
|
62
63
|
default=None,
|
63
64
|
)
|
64
|
-
sac: bool | None =
|
65
|
-
description="Typically used in concrete sidewalks and barrier curbs.",
|
65
|
+
sac: bool | None = pydantic.Field(
|
66
|
+
description="Typically used in concrete sidewalks and barrier curbs.",
|
67
|
+
examples=[True],
|
68
|
+
default=None,
|
66
69
|
)
|
67
|
-
pav: bool | None =
|
68
|
-
oil: bool | None =
|
70
|
+
pav: bool | None = pydantic.Field(description="Typically used in pervious concrete", examples=[True], default=None)
|
71
|
+
oil: bool | None = pydantic.Field(
|
69
72
|
description="Concretes for use in creation, maintenance, and decommissioning of "
|
70
73
|
"petroleum extraction wells and similar applications. Includes foamed "
|
71
74
|
"cement; often called cement in the drilling industry. Differs from "
|
72
75
|
"flowable fill and grout in that it contains no sand or other aggregates.",
|
73
|
-
|
76
|
+
examples=[True],
|
74
77
|
default=None,
|
75
78
|
)
|
76
|
-
grt: bool | None =
|
79
|
+
grt: bool | None = pydantic.Field(
|
77
80
|
description="Cement grouting is a slurry that is placed as a flowable liquid. It is "
|
78
81
|
"an effective material for filling and strengthening granular soils, "
|
79
82
|
"voids in rocks, foundation underpinnings, and other underground voids. "
|
80
83
|
"Also called structural grout, these materials typically impart"
|
81
84
|
" significant strength to the system",
|
82
|
-
|
85
|
+
examples=[True],
|
83
86
|
default=None,
|
84
87
|
)
|
85
|
-
ota: bool | None =
|
86
|
-
description="Typical application not covered by other values.",
|
88
|
+
ota: bool | None = pydantic.Field(
|
89
|
+
description="Typical application not covered by other values.",
|
90
|
+
examples=[True],
|
91
|
+
default=None,
|
87
92
|
)
|
88
93
|
|
89
94
|
|
90
95
|
class Cementitious(BaseOpenEpdSchema):
|
91
96
|
"""List of cementitious materials, and proportion by mass."""
|
92
97
|
|
93
|
-
opc:
|
94
|
-
default=None,
|
98
|
+
opc: float | None = pydantic.Field(
|
99
|
+
default=None,
|
100
|
+
description="Ordinary Gray Portland Cement",
|
101
|
+
examples=[0.5],
|
102
|
+
ge=0,
|
103
|
+
le=1,
|
95
104
|
)
|
96
|
-
wht:
|
97
|
-
ggbs:
|
98
|
-
default=None,
|
105
|
+
wht: float | None = pydantic.Field(default=None, description="White Portland Cement", examples=[0.5], ge=0, le=1)
|
106
|
+
ggbs: float | None = pydantic.Field(
|
107
|
+
default=None,
|
108
|
+
description="Ground Granulated Blast Furnace Slag",
|
109
|
+
examples=[0.5],
|
110
|
+
ge=0,
|
111
|
+
le=1,
|
99
112
|
)
|
100
|
-
flyAsh:
|
101
|
-
default=None,
|
113
|
+
flyAsh: float | None = pydantic.Field(
|
114
|
+
default=None,
|
115
|
+
description="Fly Ash, including types F, CL, and CH",
|
116
|
+
examples=[0.5],
|
117
|
+
ge=0,
|
118
|
+
le=1,
|
102
119
|
)
|
103
|
-
siFume:
|
104
|
-
gg45:
|
105
|
-
default=None,
|
120
|
+
siFume: float | None = pydantic.Field(default=None, description="Silica Fume", examples=[0.5], ge=0, le=1)
|
121
|
+
gg45: float | None = pydantic.Field(
|
122
|
+
default=None,
|
123
|
+
description="Ground Glass, 45um or smaller",
|
124
|
+
examples=[0.5],
|
125
|
+
ge=0,
|
126
|
+
le=1,
|
106
127
|
)
|
107
|
-
natPoz:
|
108
|
-
mk:
|
109
|
-
CaCO3:
|
110
|
-
other:
|
128
|
+
natPoz: float | None = pydantic.Field(default=None, description="Natural pozzolan", examples=[0.5], ge=0, le=1)
|
129
|
+
mk: float | None = pydantic.Field(default=None, description="Metakaolin", examples=[0.5], ge=0, le=1)
|
130
|
+
CaCO3: float | None = pydantic.Field(default=None, description="Limestone", examples=[0.5], ge=0, le=1)
|
131
|
+
other: float | None = pydantic.Field(default=None, description="Other SCMs", examples=[0.5], ge=0, le=1)
|
@@ -15,16 +15,16 @@
|
|
15
15
|
#
|
16
16
|
__all__ = ("AggregatesRangeV1",)
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
import pydantic
|
20
19
|
|
21
|
-
from openepd.compat.pydantic import pyd
|
22
20
|
from openepd.model.common import RangeRatioFloat
|
23
21
|
from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
|
24
22
|
from openepd.model.specs.enums import AggregateGradation, AggregateWeightClassification
|
25
23
|
from openepd.model.specs.singular.aggregates import AggregateApplication
|
26
24
|
from openepd.model.validation.quantity import AmountRangeLengthMm
|
27
25
|
|
26
|
+
# NB! This is a generated code. Do not edit it manually. Please see src/openepd/model/specs/README.md
|
27
|
+
|
28
28
|
|
29
29
|
class AggregatesRangeV1(BaseOpenEpdHierarchicalSpec):
|
30
30
|
"""
|
@@ -37,20 +37,20 @@ class AggregatesRangeV1(BaseOpenEpdHierarchicalSpec):
|
|
37
37
|
|
38
38
|
_EXT_VERSION = "1.0"
|
39
39
|
|
40
|
-
recycled_content: RangeRatioFloat | None =
|
40
|
+
recycled_content: RangeRatioFloat | None = pydantic.Field(
|
41
41
|
default=None, description="Percent of total mass that is recycled aggregate"
|
42
42
|
)
|
43
|
-
nominal_max_size: AmountRangeLengthMm | None =
|
43
|
+
nominal_max_size: AmountRangeLengthMm | None = pydantic.Field(
|
44
44
|
default=None,
|
45
45
|
description="Nominal maximum aggregate size is defined as one sieve size smaller than the maximum aggregate size. The maximum aggregate size is defined as the smallest sieve size that requires 100% passing.",
|
46
46
|
)
|
47
|
-
weight_classification: list[AggregateWeightClassification] | None =
|
48
|
-
gradation: list[AggregateGradation] | None =
|
49
|
-
manufactured: bool | None =
|
47
|
+
weight_classification: list[AggregateWeightClassification] | None = pydantic.Field(default=None)
|
48
|
+
gradation: list[AggregateGradation] | None = pydantic.Field(default=None)
|
49
|
+
manufactured: bool | None = pydantic.Field(
|
50
50
|
default=None,
|
51
51
|
description="Aggregate produced via expansion or sintering at high temperatures of the following materials: clay, shale, slate, perlite, vermiculite, or slag. Typically used to produce lightweight aggregate",
|
52
52
|
)
|
53
|
-
slag: bool | None =
|
53
|
+
slag: bool | None = pydantic.Field(
|
54
54
|
default=None,
|
55
55
|
description="Pelletized, foamed, and granulated blast furnace slag can be used as construction aggregate.",
|
56
56
|
)
|