openepd 6.14.0__py3-none-any.whl → 6.15.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 (60) hide show
  1. openepd/__version__.py +1 -1
  2. openepd/api/average_dataset/generic_estimate_sync_api.py +2 -1
  3. openepd/api/average_dataset/industry_epd_sync_api.py +2 -1
  4. openepd/api/base_sync_client.py +10 -8
  5. openepd/api/common.py +17 -11
  6. openepd/api/dto/common.py +1 -1
  7. openepd/api/epd/sync_api.py +2 -1
  8. openepd/bundle/base.py +5 -4
  9. openepd/bundle/reader.py +13 -7
  10. openepd/bundle/writer.py +11 -6
  11. openepd/compat/pydantic.py +1 -1
  12. openepd/m49/__init__.py +2 -0
  13. openepd/m49/const.py +1 -1
  14. openepd/m49/utils.py +16 -10
  15. openepd/model/base.py +19 -15
  16. openepd/model/common.py +22 -19
  17. openepd/model/declaration.py +2 -2
  18. openepd/model/epd.py +2 -1
  19. openepd/model/factory.py +5 -3
  20. openepd/model/lcia.py +7 -6
  21. openepd/model/org.py +6 -3
  22. openepd/model/pcr.py +2 -2
  23. openepd/model/specs/__init__.py +36 -0
  24. openepd/model/specs/asphalt.py +3 -3
  25. openepd/model/specs/base.py +2 -1
  26. openepd/model/specs/enums.py +695 -695
  27. openepd/model/specs/range/accessories.py +1 -1
  28. openepd/model/specs/range/aluminium.py +1 -1
  29. openepd/model/specs/range/cladding.py +10 -10
  30. openepd/model/specs/range/cmu.py +0 -3
  31. openepd/model/specs/range/concrete.py +1 -1
  32. openepd/model/specs/range/conveying_equipment.py +2 -2
  33. openepd/model/specs/range/electrical.py +18 -18
  34. openepd/model/specs/range/electrical_transmission_and_distribution_equipment.py +1 -1
  35. openepd/model/specs/range/finishes.py +16 -16
  36. openepd/model/specs/range/fire_and_smoke_protection.py +3 -3
  37. openepd/model/specs/range/furnishings.py +7 -7
  38. openepd/model/specs/range/manufacturing_inputs.py +4 -4
  39. openepd/model/specs/range/masonry.py +1 -1
  40. openepd/model/specs/range/mechanical.py +6 -6
  41. openepd/model/specs/range/network_infrastructure.py +3 -3
  42. openepd/model/specs/range/openings.py +17 -17
  43. openepd/model/specs/range/other_materials.py +4 -4
  44. openepd/model/specs/range/plumbing.py +5 -5
  45. openepd/model/specs/range/precast_concrete.py +2 -2
  46. openepd/model/specs/range/steel.py +16 -11
  47. openepd/model/specs/range/thermal_moisture_protection.py +12 -12
  48. openepd/model/specs/range/wood.py +4 -7
  49. openepd/model/specs/singular/__init__.py +109 -1
  50. openepd/model/specs/singular/aluminium.py +2 -1
  51. openepd/model/specs/singular/steel.py +10 -2
  52. openepd/model/validation/common.py +10 -6
  53. openepd/model/validation/enum.py +4 -2
  54. openepd/model/validation/quantity.py +8 -1
  55. openepd/model/versioning.py +8 -6
  56. openepd/patch_pydantic.py +2 -1
  57. {openepd-6.14.0.dist-info → openepd-6.15.0.dist-info}/METADATA +1 -3
  58. {openepd-6.14.0.dist-info → openepd-6.15.0.dist-info}/RECORD +60 -60
  59. {openepd-6.14.0.dist-info → openepd-6.15.0.dist-info}/WHEEL +1 -1
  60. {openepd-6.14.0.dist-info → openepd-6.15.0.dist-info}/LICENSE +0 -0
@@ -13,7 +13,11 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- from typing import Any, ClassVar
16
+ from collections.abc import Sequence
17
+ import types
18
+ from typing import Any, ClassVar, TypeVar
19
+
20
+ from pydantic.v1.fields import FieldInfo
17
21
 
18
22
  from openepd.compat.pydantic import pyd
19
23
  from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
@@ -59,6 +63,8 @@ from openepd.model.specs.singular.wood_joists import WoodJoistsV1
59
63
 
60
64
  __all__ = ("Specs",)
61
65
 
66
+ TValue = TypeVar("TValue")
67
+
62
68
 
63
69
  class Specs(BaseOpenEpdHierarchicalSpec):
64
70
  """Material specific specs."""
@@ -137,3 +143,105 @@ class Specs(BaseOpenEpdHierarchicalSpec):
137
143
  continue
138
144
  set_safely(values, new_key_spec, old_value)
139
145
  return values
146
+
147
+ def get_by_spec_path(
148
+ self,
149
+ path: str | Sequence[str],
150
+ *,
151
+ delimiter: str = ".",
152
+ asserted_type: type[TValue] | None = None,
153
+ ensure_path: bool = True,
154
+ ) -> TValue | None:
155
+ """
156
+ Access specific property of the spec by a path, which can be string-separated or sequence of keys.
157
+
158
+ :param path: The path to access, either as a string with delimiters (e.g. "Concrete.strength_28d")
159
+ or sequence of keys (e.g. ["Concrete", "strength_28d"])
160
+ :param delimiter: String separator used when path is provided as a string (default ".")
161
+ :param asserted_type: Type to validate the returned value against (optional)
162
+ :param ensure_path: If True, validates that path exists in the spec schema before accessing (default True)
163
+ :return: Value at the specified path if found, None if path resolves to None
164
+ :raises KeyError: If ensure_path=True and path does not exist in schema
165
+ :raises TypeError: If asserted_type is provided and value type doesn't match
166
+ :raises ValueError: If path is not string or sequence
167
+
168
+ Example usage:
169
+ >>> specs.get_by_spec_path("Concrete.strength_28d")
170
+ >>> specs.get_by_spec_path(["Concrete", "strength_28d"])
171
+ >>> specs.get_by_spec_path("Concrete.strength_28d", asserted_type=str)
172
+ """
173
+ keys = self._path_to_keys(path, delimiter)
174
+
175
+ if ensure_path:
176
+ self._ensure_path(keys)
177
+
178
+ result: Any = self
179
+ for key in self._path_to_keys(path, delimiter):
180
+ result = getattr(result, key, None)
181
+ if result is None:
182
+ return None
183
+
184
+ if not asserted_type:
185
+ return result
186
+
187
+ if isinstance(result, asserted_type):
188
+ return result
189
+
190
+ msg = f"Expected {asserted_type} but got {type(result)}"
191
+ raise TypeError(msg)
192
+
193
+ def _ensure_path(self, keys: Sequence[str]) -> None:
194
+ """
195
+ Validate if a sequence of keys exists in the spec schema structure.
196
+
197
+ :param keys: Sequence of string keys representing path in spec schema
198
+ :raises KeyError: If path specified by keys does not exist in schema
199
+
200
+ This internal method walks through the schema structure following the provided keys
201
+ sequence, checking if each key exists at the corresponding level. For UnionType fields,
202
+ it extracts the non-None type and continues validation if it's a BaseModel.
203
+ """
204
+ klass = self.__class__
205
+
206
+ fields: dict[str, FieldInfo] = klass.__fields__ # type: ignore[assignment]
207
+
208
+ field: FieldInfo | None
209
+ for i, key in enumerate(keys, start=1):
210
+ field = fields.get(key)
211
+ if field is None:
212
+ msg = f"Path {'.'.join(keys)} does not exist in {klass.__name__} spec"
213
+ raise KeyError(msg)
214
+
215
+ assert hasattr(field, "annotation"), "Annotation field is required"
216
+ if isinstance(field.annotation, types.UnionType):
217
+ target_type = next(item for item in field.annotation.__args__ if item is not None)
218
+ else:
219
+ target_type = field.annotation
220
+
221
+ if issubclass(target_type, pyd.BaseModel):
222
+ fields = target_type.__fields__
223
+ elif i == len(keys):
224
+ return None
225
+ else:
226
+ msg = f"Path {'.'.join(keys)} does not exist in {klass.__name__} spec"
227
+ raise KeyError(msg)
228
+
229
+ return None
230
+
231
+ def _path_to_keys(self, path: str | Sequence[str], delimiter: str) -> Sequence[str]:
232
+ """
233
+ Convert path parameter to sequence of keys.
234
+
235
+ :param path: Path to convert, either string to split by delimiter or sequence of keys
236
+ :param delimiter: String separator used to split path if string is provided
237
+ :return: Sequence of string keys
238
+ :raises ValueError: If a path is not string or sequence
239
+ """
240
+ match path:
241
+ case str():
242
+ return path.split(delimiter)
243
+ case Sequence():
244
+ return path
245
+ case _:
246
+ msg = f"Unsupported path type: {type(path)}"
247
+ raise ValueError(msg)
@@ -25,7 +25,8 @@ class AluminiumBilletsV1(BaseOpenEpdHierarchicalSpec):
25
25
 
26
26
 
27
27
  class AluminiumExtrusionsV1(BaseOpenEpdHierarchicalSpec):
28
- """Extruded aluminum products used in construction.
28
+ """
29
+ Extruded aluminum products used in construction.
29
30
 
30
31
  Includes range of finish options including mill finish, painted, and anodized.
31
32
  """
@@ -85,7 +85,8 @@ class HotRolledSectionsV1(BaseOpenEpdHierarchicalSpec, SteelFabricatedMixin):
85
85
 
86
86
 
87
87
  class PlateSteelV1(BaseOpenEpdHierarchicalSpec, SteelFabricatedMixin):
88
- """Plate Steels.
88
+ """
89
+ Plate Steels.
89
90
 
90
91
  Flat hot-rolled steel, typically thicker than 'sheet', made by compressing multiple steel
91
92
  layers together into one.
@@ -250,10 +251,16 @@ class OtherSteelV1(BaseOpenEpdHierarchicalSpec):
250
251
  _EXT_VERSION = "1.0"
251
252
 
252
253
 
254
+ class CrudeSteelV1(BaseOpenEpdHierarchicalSpec):
255
+ """Steel ingots, billets, blooms, and slabs for use in manufacturing steel products."""
256
+
257
+ _EXT_VERSION = "1.0"
258
+
259
+
253
260
  class SteelV1(BaseOpenEpdHierarchicalSpec):
254
261
  """Broad category for construction materials made from steel and its alloys."""
255
262
 
256
- _EXT_VERSION = "1.1"
263
+ _EXT_VERSION = "1.2"
257
264
 
258
265
  # Own fields:
259
266
  yield_tensile_str: PressureMPaStr | None = pyd.Field(
@@ -303,3 +310,4 @@ class SteelV1(BaseOpenEpdHierarchicalSpec):
303
310
  RebarSteel: RebarSteelV1 | None = None
304
311
  WireMeshSteel: WireMeshSteelV1 | None = None
305
312
  OtherSteel: OtherSteelV1 | None = None
313
+ 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 typing import Annotated, Any, Callable, Type, TypeAlias
16
+ from collections.abc import Callable
17
+ from typing import Annotated, Any, TypeAlias
17
18
 
18
19
  from openepd.compat.pydantic import pyd
19
20
  from openepd.model.versioning import Version
@@ -24,7 +25,8 @@ def together_validator(field1: str, field2: Any, values: dict[str, Any]) -> Any:
24
25
  value1 = values.get(field1)
25
26
  value2 = values.get(field2)
26
27
  if value1 is not None and value2 is None or value1 is None and value2 is not None:
27
- raise ValueError(f"Both or neither {field1} and {field2} days must be provided together")
28
+ msg = f"Both or neither {field1} and {field2} days must be provided together"
29
+ raise ValueError(msg)
28
30
 
29
31
 
30
32
  def validate_version_format(v: str) -> str:
@@ -33,17 +35,19 @@ def validate_version_format(v: str) -> str:
33
35
  return v
34
36
 
35
37
 
36
- def validate_version_compatibility(class_version_attribute_name: str) -> Callable[[Type, str], str]:
38
+ def validate_version_compatibility(class_version_attribute_name: str) -> Callable[[type, str], str]:
37
39
  """Ensure that the object which is passed for parsing and validation is compatible with the class."""
38
40
 
39
41
  # we need closure to pass property name, since actual class will only be available in runtime
40
- def internal_validate_version_compatibility(cls: Type, v: str) -> str:
42
+ def internal_validate_version_compatibility(cls: type, v: str) -> str:
41
43
  if not hasattr(cls, class_version_attribute_name):
42
- raise ValueError(f"Class {cls} must declare a class var extension var named {class_version_attribute_name}")
44
+ msg = f"Class {cls} must declare a class var extension var named {class_version_attribute_name}"
45
+ raise ValueError(msg)
43
46
 
44
47
  class_version = getattr(cls, class_version_attribute_name)
45
48
  if Version.parse_version(v).major != Version.parse_version(class_version).major:
46
- raise ValueError(f"Extension version {v} does not match class version {class_version}")
49
+ msg = f"Extension version {v} does not match class version {class_version}"
50
+ raise ValueError(msg)
47
51
  return v
48
52
 
49
53
  return internal_validate_version_compatibility
@@ -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 typing import Any, Callable
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
- raise ValueError(f"Values {', '.join(matching_from_group)} are not allowed together.")
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,7 +14,8 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  from abc import ABC, abstractmethod
17
- from typing import TYPE_CHECKING, Any, Callable, ClassVar
17
+ from collections.abc import Callable
18
+ from typing import TYPE_CHECKING, Any, ClassVar
18
19
 
19
20
  from openepd.compat.pydantic import pyd
20
21
  from openepd.model.base import BaseOpenEpdSchema
@@ -55,8 +56,10 @@ class QuantityValidator(ABC):
55
56
  dimensionality: The dimensionality to validate against, like "kg"
56
57
  Returns:
57
58
  None if the value is valid, raises an error otherwise.
59
+
58
60
  Raises:
59
61
  ValueError: If the value is not valid.
62
+
60
63
  """
61
64
  pass
62
65
 
@@ -70,8 +73,10 @@ class QuantityValidator(ABC):
70
73
  min_value: The value to compare with, like "102.4 kg"
71
74
  Returns:
72
75
  None if the value is valid, raises an error otherwise.
76
+
73
77
  Raises:
74
78
  ValueError: If the value is not valid.
79
+
75
80
  """
76
81
  pass
77
82
 
@@ -85,8 +90,10 @@ class QuantityValidator(ABC):
85
90
  max_value: The value to compare with, like "0.4 kg"
86
91
  Returns:
87
92
  None if the value is valid, raises an error otherwise.
93
+
88
94
  Raises:
89
95
  ValueError: If the value is not valid.
96
+
90
97
  """
91
98
  pass
92
99
 
@@ -44,7 +44,8 @@ class Version(NamedTuple):
44
44
 
45
45
  @staticmethod
46
46
  def parse_version(version: str) -> "Version":
47
- """Parse the version of extension or the format.
47
+ """
48
+ Parse the version of extension or the format.
48
49
 
49
50
  Version is expected to be major.minor
50
51
 
@@ -53,9 +54,11 @@ class Version(NamedTuple):
53
54
  """
54
55
  splits = version.split(".", 1) if isinstance(version, str) else None
55
56
  if len(splits) != 2:
56
- raise ValueError(f"Invalid version: {version}")
57
+ msg = f"Invalid version: {version}"
58
+ raise ValueError(msg)
57
59
  if not splits[0].isdigit() or not splits[1].isdigit():
58
- raise ValueError(f"Invalid version: {version}")
60
+ msg = f"Invalid version: {version}"
61
+ raise ValueError(msg)
59
62
  return Version(major=int(splits[0]), minor=int(splits[1]))
60
63
 
61
64
  def __str__(self) -> str:
@@ -112,9 +115,8 @@ class OpenEpdVersions(Version, ReprEnum):
112
115
  for x in cls:
113
116
  if x.value.major == branch:
114
117
  return x.value
115
- raise ValueError(
116
- f"No version {branch}.x is not supported. Supported versions are: {', '.join(str(x.value) for x in cls)}"
117
- )
118
+ msg = f"No version {branch}.x is not supported. Supported versions are: {', '.join(str(x.value) for x in cls)}"
119
+ raise ValueError(msg)
118
120
 
119
121
  @classmethod
120
122
  def get_current(cls) -> Version:
openepd/patch_pydantic.py CHANGED
@@ -86,10 +86,11 @@ def patch_pydantic_metaclass_validator():
86
86
  if isinstance(attr, model_field_classes_tuple):
87
87
  continue
88
88
 
89
- raise NameError(
89
+ msg = (
90
90
  f'Field name "{field_name}" shadows a BaseModel attribute; '
91
91
  f"use a different field name with \"alias='{field_name}'\"."
92
92
  )
93
+ raise NameError(msg)
93
94
 
94
95
  pyd.main.validate_field_name = pydantic_utils__validate_field_name
95
96
  pydantic_utils.validate_field_name = pydantic_utils__validate_field_name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 6.14.0
3
+ Version: 6.15.0
4
4
  Summary: Python library to work with OpenEPD format
5
5
  Home-page: https://github.com/cchangelabs/openepd
6
6
  License: Apache-2.0
@@ -15,8 +15,6 @@ Classifier: License :: OSI Approved :: Apache Software License
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3.11
18
- Classifier: Programming Language :: Python :: 3.12
19
- Classifier: Programming Language :: Python :: 3.13
20
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
19
  Provides-Extra: api-client
22
20
  Requires-Dist: email-validator (>=1.3.1)
@@ -1,23 +1,23 @@
1
1
  openepd/__init__.py,sha256=fhxfEyEurLvSfvQci-vb3njzl_lvhcLXiZrecCOaMU8,794
2
- openepd/__version__.py,sha256=j453SSnXhKMHPbf1O03SN8RtQbB3r2ZWnWQ2okYB0mw,639
2
+ openepd/__version__.py,sha256=iyY3VSoCvm9hVasih1ViXL90QibEUft4FAGomBc7DNg,639
3
3
  openepd/api/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
4
4
  openepd/api/average_dataset/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
5
- openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=KHCmSKMOJTQct6vhdhAatAENoouStc_yVRza5AFNoIo,7953
6
- openepd/api/average_dataset/industry_epd_sync_api.py,sha256=CG5c6FQD3I8sl9PKI9VHFUaJlFrnF8E14i4k6Uv0B74,6286
7
- openepd/api/base_sync_client.py,sha256=E6yrqME-c1emV1BrI33dwjdu6wcFoRkqWtg1zFyki2Y,20992
5
+ openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=_eZt_jGVL1a3p9cr-EF39Ve9Vl5sB8zwzTc_slnRL50,7975
6
+ openepd/api/average_dataset/industry_epd_sync_api.py,sha256=8SJaWfc9yJwtWbODM4oNXLBWiVg6_JUB_IalK1Rqli4,6308
7
+ openepd/api/base_sync_client.py,sha256=ChXvtOeKAIPe2grr05fb0AosFlOt431_VSm-8zra450,21050
8
8
  openepd/api/category/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
9
9
  openepd/api/category/dto.py,sha256=-nsSNH1zWIluFuF50qmnIcvloX08Jk_KV5mebJqzLe4,850
10
10
  openepd/api/category/sync_api.py,sha256=XlT5a_IkfaVARrZY0hjDUzDVP2ThkR2j_MRNqz6zkTE,1371
11
- openepd/api/common.py,sha256=bLSER3RQQFR4lyEuxQPKNjTaa3S0K8fFi8x4QRAPM_g,8812
11
+ openepd/api/common.py,sha256=KfV-HX93QtQp1vnmfAp-pdpDBvpfzahbXavCXbLt6L0,8943
12
12
  openepd/api/dto/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
13
13
  openepd/api/dto/base.py,sha256=w-Ci0MN2vTIQ0Vl0YKLUXVG_fC0OxiwojT9SX3lWktg,1033
14
- openepd/api/dto/common.py,sha256=3d-frR8kqVw0TFwFE7u7ovxKQM0ZAzNcwaLiGgSO-zE,4488
14
+ openepd/api/dto/common.py,sha256=0XGGawcj7KP-P864yqvNusEaMFj6ImfsfbcmebwYqxY,4502
15
15
  openepd/api/dto/meta.py,sha256=IrGJtfl6-mBXLSWZjcyr08WvvOh9VL0LJnx5ubhJqco,2160
16
16
  openepd/api/dto/mf.py,sha256=59YvIrH5teHlpxINihxryFyCjs7jBZZuqYIO1K-daA8,1994
17
17
  openepd/api/dto/params.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
18
18
  openepd/api/epd/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
19
19
  openepd/api/epd/dto.py,sha256=MqhHjaNdtOc-KT2zNI88EB9-1d2a6CS2zzSus8HefBo,4874
20
- openepd/api/epd/sync_api.py,sha256=coM-4VDn_sn3DeBbA4YnStsMBqX7zQZSmUnUXHi0gM8,7320
20
+ openepd/api/epd/sync_api.py,sha256=kBsx43q0cBm51hl3HVvzMIDrMMRi8NMyudPmHYd0qqU,7342
21
21
  openepd/api/errors.py,sha256=BgZeNfMNAKVPfhpuiVapCXNBSsXygAOWql-gy7m9j7E,2868
22
22
  openepd/api/pcr/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
23
23
  openepd/api/pcr/sync_api.py,sha256=MyBOlBqdJt35-fXk-Vr-RpiKUbN_XlilUwwFGvVROdQ,1557
@@ -25,74 +25,74 @@ openepd/api/sync_client.py,sha256=reD_OXsaVOvUvnC-cyp5aq8sKSOH2Z8xmImxV2ClQIM,31
25
25
  openepd/api/test/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
26
26
  openepd/api/utils.py,sha256=xOU8ihC0eghsoaCFhC85PU4WYRwNxVEpfK3gzq4e9ik,2092
27
27
  openepd/bundle/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
28
- openepd/bundle/base.py,sha256=Ou2zlAV7VRKp7Lxu8h4k56OLEMwn5F1nrEEF_ies_lE,6869
28
+ openepd/bundle/base.py,sha256=ovURf721k9XWe0C8-tmik_bEOrHdOtF1jbN03T5G7M4,6918
29
29
  openepd/bundle/model.py,sha256=_fQWW1KsxKquFFB6JtU3dyc82re1vqmwMpxe6zUEfSE,2605
30
- openepd/bundle/reader.py,sha256=sXhqwxXFN2GdNS0cQHdaxKEtNM4jzhcML1yN4XAIRzE,6687
31
- openepd/bundle/writer.py,sha256=gHK1D-F-td2C18QFWerg666JUTLaGUkTUSQURJi9o74,8136
30
+ openepd/bundle/reader.py,sha256=YvTXglxp8HLxkaOUdbvOuyA9qeN3vt_PjlAroOSzNO0,6822
31
+ openepd/bundle/writer.py,sha256=qfQWlGnbQxzim8mMbDKRyBpdEXDe60nyNbgjAbG0eq8,8245
32
32
  openepd/compat/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
33
33
  openepd/compat/compat_functional_validators.py,sha256=aWg3a80fqT8zjN0S260N-Ad2WFKAaB8ByN7ArBW3NMA,834
34
- openepd/compat/pydantic.py,sha256=dNwPXK1X5xq9sdkd0kcbKQAUIter1GAfcxXOl6hmITQ,1146
35
- openepd/m49/__init__.py,sha256=vkXC6i8OeCl5K88JUIRN_NKfsAIpNIaN-fyPmmd-Lfk,689
36
- openepd/m49/const.py,sha256=buspTHOOWhkBXWUIS0oqvQ0y1L7y70Y_PXilkiBIKD4,31819
37
- openepd/m49/utils.py,sha256=Qm8HvxAZlQncsyUYDO0lG0feMFFnT4HQPNSMp78W4zU,7111
34
+ openepd/compat/pydantic.py,sha256=HZJmAiYO7s-LLcFHuj3iXS4MGOITExZYn2rPmteoqNI,1146
35
+ openepd/m49/__init__.py,sha256=AApOMp9PJPMXZbPB4piedqKtgHE01mlj_MyF3kf519U,718
36
+ openepd/m49/const.py,sha256=bkYu6J7dQNVb2-nNkjy97uMpt64vICX5o-PHr0lk_90,31833
37
+ openepd/m49/utils.py,sha256=vQl0wMXtYS2b7NeLIWilDNUopq3MATmLnhEFcMYTeZA,7256
38
38
  openepd/model/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
39
- openepd/model/base.py,sha256=1GeaEDn-ppy94GaOaZI1y6Yew_0eBBho1COaxfzzLCw,9834
39
+ openepd/model/base.py,sha256=6rP6r-7NwKC6JLFB24v2w4Z-_f_w6ZSNLte5zyj5o70,9928
40
40
  openepd/model/category.py,sha256=reeOVRDuZPYU77EMwG0K5VjnK2H9yOGxT0PJXXqrjEk,1639
41
- openepd/model/common.py,sha256=2MYjaXXq3_ECjTD7lI4SSZm3wguLrPraaObUpqF0t5g,13062
42
- openepd/model/declaration.py,sha256=56cjshR21PxTVCM5xOq_JH7Rw4gw1q_9jdroHaDDOiI,13832
43
- openepd/model/epd.py,sha256=qYYJQKbcFNOU_qS5Ag9CXn7Tx0TkIoUOZQEDGJI-xZw,12290
44
- openepd/model/factory.py,sha256=doexyqZXJVGd45T1JsbjuyGUjEykW-MerKUq4SQHhRY,2656
41
+ openepd/model/common.py,sha256=jblgVf_ASMelxe_-mk6fnOIyM4n0TY4PJ8MeLX8O92c,13134
42
+ openepd/model/declaration.py,sha256=72oR19n0CfJx4DhMXGYrLYY_sUB4awZzpr4Tr3Jcnks,13814
43
+ openepd/model/epd.py,sha256=_1P9-etXfLAVmg44pglnBUvoEyQ50odNBsUrv_OeS9M,12308
44
+ openepd/model/factory.py,sha256=UWSGpfCr3GiMTP4rzBkwqxzbXB6GKZ_5Okb1Dqa_4aA,2701
45
45
  openepd/model/generic_estimate.py,sha256=zLGTyf4Uzmp2C0m-J1ePWItSz2RGdZ0OiGPWC5nhKHk,3992
46
46
  openepd/model/geography.py,sha256=Jx7NIDdk_sIvwyh-7YxnIjAwIHW2HCQK7UtFGM2xKtw,42095
47
47
  openepd/model/industry_epd.py,sha256=QZr7OhgGkzqZ8H5p6dCIVk9zSHEYtK3y9Nk-DvkFMyk,4011
48
- openepd/model/lcia.py,sha256=sUuVOJivfyx1m2l83YdPyTgkJBOn7mJGVFxvbCo_bCk,26107
49
- openepd/model/org.py,sha256=MtaUrD8IdSbcMJEwL2lnXOIXNfE8wpzrepFSe2qh2uc,5342
50
- openepd/model/pcr.py,sha256=b8WmeII8MZ3rJFWxugqv_Z0ETan8NMWj9L6mSrhneJk,5494
48
+ openepd/model/lcia.py,sha256=jgxTVoY2gCgfPCLrV5xRYGHbxntellGTfgLUGU9J22Y,26152
49
+ openepd/model/org.py,sha256=nm3B4HdJDASyr4SIosE64BK45tR4bv9CsFBls0umoG8,5408
50
+ openepd/model/pcr.py,sha256=7nf6ATofdrlPt81vdU6p0E8n_ftFEuCEIKxtYlFwclw,5476
51
51
  openepd/model/specs/README.md,sha256=UGhSiFJ9hOxT1mZl-5ZrhkOrPKf1W_gcu5CI9hzV7LU,2430
52
- openepd/model/specs/__init__.py,sha256=YcAvn0h_Bhz_Cb4-uEl8DiBI82nXogQsocB-c2zvr_A,3094
53
- openepd/model/specs/asphalt.py,sha256=bfNnTAIT6BN2trWOAoYOjDgfbhvIbBw4hfFaTn9Ecpk,3420
54
- openepd/model/specs/base.py,sha256=cJTv4kO3QyS0vqfytTlKrOBu-2sBwx7NM0_YZS4i3rY,2652
52
+ openepd/model/specs/__init__.py,sha256=toVWd8_jxmAf7gRwpoXQpLfZW6Cl-NwveoduMXhECms,3903
53
+ openepd/model/specs/asphalt.py,sha256=eHhcITbBrNYR5N6x4Q2BxpsR64BR9OkjJ4bvPRYOqMg,3411
54
+ openepd/model/specs/base.py,sha256=10IDyRFKQgFnyIPSqpeayP8Og1BDgs1EepXX5dyCMM4,2674
55
55
  openepd/model/specs/concrete.py,sha256=D9jbhZDtTXNBoAgljQBPxsmGsMvLSIAP5H53ZYiXcGI,5336
56
- openepd/model/specs/enums.py,sha256=_WMe0l8ZKPIGQG53A1rB_Sv_p2izr8Zemg9AEEYOU2g,63638
56
+ openepd/model/specs/enums.py,sha256=H6PPr_wRnGFXIjFqMoVAgVNxqtUedkq9dKN9KVs_G_o,62893
57
57
  openepd/model/specs/range/__init__.py,sha256=ZXgsyzn_c6H2SPCo5hTVZOjRqlCf0HvVVMDQ4RGaPSU,4502
58
- openepd/model/specs/range/accessories.py,sha256=wnOv1V_uatA6g_9QVfZaSp-rNLbyZ_KS-t3wlHaeEsI,2498
58
+ openepd/model/specs/range/accessories.py,sha256=hZYz8mvAqrfLFiOIZ9qQZ59zmEiu0xE61Ko9cQ7NSKU,2498
59
59
  openepd/model/specs/range/aggregates.py,sha256=udVbsYc1Lyrd6a4YZBGNDQ3sBi-L3WLub_e1ecq7U-Q,2549
60
- openepd/model/specs/range/aluminium.py,sha256=m2u43hHAcPmvm9dkhcqMojTRuJmX4gofW_uU5AZzqG8,2745
60
+ openepd/model/specs/range/aluminium.py,sha256=Z3laZKXoPtfmOLLr4c4uf7Z-8TNmfz51X-_yd7GQIj8,2745
61
61
  openepd/model/specs/range/asphalt.py,sha256=DN3--5g0WL2AQ8Vc23M899rPqxCaFgEhaYqV8vWRbZY,2934
62
62
  openepd/model/specs/range/bulk_materials.py,sha256=SuKhmJXMa9jl0CrkYr3QVvPX_GDbr7KATzrSS-fJEU4,1051
63
63
  openepd/model/specs/range/cast_decks_and_underlayment.py,sha256=37fx7jDRy6xryZTVweW_vu78h0kRs5vQurGS-Ypayog,1132
64
- openepd/model/specs/range/cladding.py,sha256=3rMnT-km0tZ9b_Wb-i8vMxO-Uw94SPJqCYzMLDD4BOQ,7236
65
- openepd/model/specs/range/cmu.py,sha256=4bf9z1ps_WTYfhdtG_duqEwTahIBrykm6v7c-uyeyWY,1862
66
- openepd/model/specs/range/concrete.py,sha256=lmLEhll8xgkMu__BRbQRACvZ5u3R9ui2oVhE9qR0RMs,6907
67
- openepd/model/specs/range/conveying_equipment.py,sha256=Ly5i8yUwn-2Xjh8-mA1-rwel0eRQZ028zrEApO2XhxQ,3176
68
- openepd/model/specs/range/electrical.py,sha256=TkmXFiGbyX5rtNqVYftr37wuhwyx-3T71IfXlUufkkU,11860
69
- openepd/model/specs/range/electrical_transmission_and_distribution_equipment.py,sha256=rbdmHvz9nRMgcWrCGVnN0xXSl5ZezuwArOZ_4xCQIgM,2525
64
+ openepd/model/specs/range/cladding.py,sha256=r7M2lc77NR2GXBkgkqRzskQ6TdZeMd7pEEm8ecHb8rc,7236
65
+ openepd/model/specs/range/cmu.py,sha256=Sv4yw6121LSgYhW4J82xKsIi1KucaeDVF7xmpZtoCt8,1833
66
+ openepd/model/specs/range/concrete.py,sha256=m2JP-W4Pnoo6q3hUbkIJF4_hTwI_-7FNLGZzdp-PX1w,6907
67
+ openepd/model/specs/range/conveying_equipment.py,sha256=_rqJ9Y3kkP8E6-vkZb6Pih3JnR1nUESJoOLf-LT--sc,3176
68
+ openepd/model/specs/range/electrical.py,sha256=EI8pv9SN4lJbFNz1wlyMNAjkA0dsi84pc2J9YvtiwzY,11860
69
+ openepd/model/specs/range/electrical_transmission_and_distribution_equipment.py,sha256=xDdyLj6oJRmdybq7W91MtgE80FDpaG6ii5hE921aRGQ,2525
70
70
  openepd/model/specs/range/electricity.py,sha256=yn_S25C_tZqseb8hiJ1yiHszu2mQ49FOFWWCqNpOBY0,997
71
- openepd/model/specs/range/finishes.py,sha256=oCaPVYJja1KYxwEzTHCl7HtxQ2mokzeyahjyP33zHSg,21291
72
- openepd/model/specs/range/fire_and_smoke_protection.py,sha256=u5veICQznf-woYlh49S_IbvPA23CLWEy7Ngvic2FIpw,3337
73
- openepd/model/specs/range/furnishings.py,sha256=FOGfaaA2mGtlWuBuzJLxkHU3JSKzhtCDZVgpfEtR85Y,6703
71
+ openepd/model/specs/range/finishes.py,sha256=Yu0Jz8L7Eqy79n79uyoqYwpKa1UeX4m2A5CFJxn49AQ,21291
72
+ openepd/model/specs/range/fire_and_smoke_protection.py,sha256=GUap2Xrn-rFF8CMDyRcOpmQpO8JgZ7PSUXGr_SKUzws,3337
73
+ openepd/model/specs/range/furnishings.py,sha256=_HdPg1_LepLgdo5tV59oRer1PRYniIM0kLEKbnlyoLM,6703
74
74
  openepd/model/specs/range/grouting.py,sha256=BQPxH6BvlXpdhLEZBui9zTuY93K_9syjoa6rdnF8GGY,1095
75
- openepd/model/specs/range/manufacturing_inputs.py,sha256=xzgkNz7yG8cp715hxS0LtJX9nfJ5RQR8GxlD2bAduwE,5574
76
- openepd/model/specs/range/masonry.py,sha256=IyjQMb8Mx3tpJlHIIam0OrMkFsJXKvc0WXRLRBupozY,2867
75
+ openepd/model/specs/range/manufacturing_inputs.py,sha256=RFqWTQij2Zc5-Y4jzOBQKC0ENV3ncg5O9yHoqdo9rUQ,5574
76
+ openepd/model/specs/range/masonry.py,sha256=P9USz744YQLBEk_XdG4v9a4ImXtMymnPC30qtbd2F6I,2867
77
77
  openepd/model/specs/range/material_handling.py,sha256=9jxRHpjMKu71B5omH55UjkNVJvaTLgTMtEidSKPFn5c,1483
78
- openepd/model/specs/range/mechanical.py,sha256=vAUXSYJXBIhDNuVJHOGeP--Pvt0YObJLdedmkXF6_9c,10267
78
+ openepd/model/specs/range/mechanical.py,sha256=kyAJj9KJ17usuKDOt7v2gAJpzSEeYO9nnTOB_pht-fc,10267
79
79
  openepd/model/specs/range/mechanical_insulation.py,sha256=S2-NkFVkjLmn_dk3gsG8C2YcV0SFXbOCgY6LKberqh8,1737
80
- openepd/model/specs/range/network_infrastructure.py,sha256=8bJGGEME7TELLxKAfKCCkZfA-K27Mp7tkC71W6YOxEc,8498
81
- openepd/model/specs/range/openings.py,sha256=tgy7XbiwPleqrsSVrKBadvmnXSyV3bnOVf84K8vwEMQ,15451
80
+ openepd/model/specs/range/network_infrastructure.py,sha256=aqXEIGqFy0gNCM_ftd3J6aT3FZf9JlT0SBOImhdkTg0,8498
81
+ openepd/model/specs/range/openings.py,sha256=4n5PEMJJFL75wMmYUcJNxdWtDMpWYZLKK4d-730KASA,15451
82
82
  openepd/model/specs/range/other_electrical_equipment.py,sha256=H4tZHcHyR2uUYHn-bQfLC6hR4tynVp_7EJbiI-YpK7Y,1001
83
- openepd/model/specs/range/other_materials.py,sha256=k7Gv6YvWy43B-QFBabBt-TkvkC450Pz2a2pz9t6r4OU,4495
84
- openepd/model/specs/range/plumbing.py,sha256=RYfP6ail7cYrwBluxmbAkC9icbxXaxdrdnf4Vqhy9ho,5342
85
- openepd/model/specs/range/precast_concrete.py,sha256=hXnljuc6djoScmx50ZWkmVjnihCTjiZV755aaKCs6uA,3763
83
+ openepd/model/specs/range/other_materials.py,sha256=RHusAyExYl9n1BDiOFDq2_znEn3MXGxEkunb3BjiC2U,4495
84
+ openepd/model/specs/range/plumbing.py,sha256=jQKrKYGDR33uh3ffo6uVyt3xuSmexkkelfNh_-omNCg,5342
85
+ openepd/model/specs/range/precast_concrete.py,sha256=nn1U1XwKqqzY1cOPP3KqHZMJq4Ut9RAox4SMVYBa5B8,3763
86
86
  openepd/model/specs/range/sheathing.py,sha256=tATL6dzKTdN0rUKZRzZd779dLhKdEavL5Bjybnt2MjU,3395
87
- openepd/model/specs/range/steel.py,sha256=tPRtWSqhVjmbbWVFoFpS7rQKDsaYn9D_6afBOYhqPug,10417
88
- openepd/model/specs/range/thermal_moisture_protection.py,sha256=WOyUzR_t39mpekg1vOrU9e529DyR1EPM0h3QAP46kdc,9409
87
+ openepd/model/specs/range/steel.py,sha256=LY54qqxL1XgkWGZ2MYH8WdsARU3lLf3R_-3pNZUyhbY,10476
88
+ openepd/model/specs/range/thermal_moisture_protection.py,sha256=aUpStISG2snc8aZ7iLCTIejurcCoMHNgRNYwp5PwgOc,9409
89
89
  openepd/model/specs/range/utility_piping.py,sha256=mQTrKbMTES_0Yta9DBnKehsmA2BAN_zYF_uPZCTKLPo,2665
90
- openepd/model/specs/range/wood.py,sha256=1ZAkUwcFF9etc7CZ1_BSvjchpnqnngfZihYZMtuLdeM,6946
90
+ openepd/model/specs/range/wood.py,sha256=ZMStFsFOw5d6tCL2P7kksBnlYhwfvWJBZqoAdqSIUDg,6917
91
91
  openepd/model/specs/range/wood_joists.py,sha256=NCBHL0gdKwdKlGCP6up_Royl9BtWUUeuFfS1r2vIZ30,1785
92
- openepd/model/specs/singular/__init__.py,sha256=igkfspzFQzoIFPU6Gd6RbxkyLr2RFPGn7brKUo_jN5s,6910
92
+ openepd/model/specs/singular/__init__.py,sha256=AUVpQi2F8oq9xoMdz5zI0FFXHQYjknPvg_1ydxwVp3A,11278
93
93
  openepd/model/specs/singular/accessories.py,sha256=xcuSJrG84oTm_w76_wlv_sItfK36gSyDmUD2TnpZnVE,2013
94
94
  openepd/model/specs/singular/aggregates.py,sha256=oSfArxvLUj63w_U0tZViRyiOpMRRjE72ncy2BimKxco,2934
95
- openepd/model/specs/singular/aluminium.py,sha256=pkcjMf_gBTler1nzbb7_XEKCpUD1hyM-tly3Twfr_lo,2403
95
+ openepd/model/specs/singular/aluminium.py,sha256=7Z3WmuW22o92cPHfR6X_OBSoer0V5llwiNdQmWgKTx8,2408
96
96
  openepd/model/specs/singular/asphalt.py,sha256=JDviENdY_2tcj5SrzgJnYJHuxTIOhLCWcXhmoSiELKk,3295
97
97
  openepd/model/specs/singular/bulk_materials.py,sha256=LKTmh432ak51L0GsVf-40389Lwx-sxZm_jSfzWNfagE,875
98
98
  openepd/model/specs/singular/cast_decks_and_underlayment.py,sha256=HjIEKekxCAKx51XEvH1tthUP6gNTbntDoi8gSu8LjZk,955
@@ -125,21 +125,21 @@ openepd/model/specs/singular/other_materials.py,sha256=_00_fCPn7G_-HVKC1cQcNvBDf
125
125
  openepd/model/specs/singular/plumbing.py,sha256=fHmKyy1aQxu8NZ3RTwxuA0CCERMgwVUdMA74kMDVc8o,4568
126
126
  openepd/model/specs/singular/precast_concrete.py,sha256=W2tKf0vOnAdfeGc1n7Pk8yx9jy44afdFB0cbwHjw1HI,7327
127
127
  openepd/model/specs/singular/sheathing.py,sha256=dfBSGElsJ-suj3WH7CZx5k3_v5E5IHVDOscwRI5yghE,3709
128
- openepd/model/specs/singular/steel.py,sha256=bPK2BUS_DfM7ulgvG-IZtB9yZETZV9HiUF-9TzodTYI,10529
128
+ openepd/model/specs/singular/steel.py,sha256=Kfnb1Tnk8eGAbFALDWffOzo1tZQdSk6MgnPldLAoe2o,10746
129
129
  openepd/model/specs/singular/thermal_moisture_protection.py,sha256=7fikgfPyopWruPzhWdyU-YWvlo5facOjXbviyl_qOEw,8195
130
130
  openepd/model/specs/singular/utility_piping.py,sha256=KunlvMGqH_Z62TecGnT_4HhsTase01aJJIGIsyY5mGY,2483
131
131
  openepd/model/specs/singular/wood.py,sha256=6bGl5TgJgAZxosh_46YcZDm57DOyFyLZ9g2W-oDlhl8,6591
132
132
  openepd/model/specs/singular/wood_joists.py,sha256=WL_l48aTuazQkWwdz5EQcGrbK5biWhqHqhWdHXITPIo,1719
133
133
  openepd/model/standard.py,sha256=LFqZKK8nYJHKvcW0BaLoFm0-TVYpQr2l9l70vHLRiNk,1688
134
134
  openepd/model/validation/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
135
- openepd/model/validation/common.py,sha256=3HYzftDMYvaX_gpl337g8AdsohMkaOoOR6pmE22Mm5c,2435
136
- openepd/model/validation/enum.py,sha256=ttODVtMEQaBemMFywGUNlXU4bAM25FiBlVDKZbOv2iY,1793
135
+ openepd/model/validation/common.py,sha256=nzZoboF8Hab8WpQA4HGkqe7hds-SLJylh_QhasrEtZs,2518
136
+ openepd/model/validation/enum.py,sha256=0nRnjwmObw8ERQYWRWbovZjm90CMHi1Sc-UeNxCFnsc,1846
137
137
  openepd/model/validation/numbers.py,sha256=r15pLe8oWY1tshazQvis_suVXpC6PUcPzKTvj3QTL9Q,851
138
- openepd/model/validation/quantity.py,sha256=vfSe-3DGQf84bCp_sMIU0ZPAA1wIilodpTjLSMoz5Jk,20194
139
- openepd/model/versioning.py,sha256=cm3LaAUODnbbu3W3pC6baJzxKusTQ1kZH-PwwScCj3c,4473
140
- openepd/patch_pydantic.py,sha256=LVqDMKn723VYYf_V-RgTLxIb1xiUtYOfPYCQP6-7RoM,4122
138
+ openepd/model/validation/quantity.py,sha256=ve0sPN9hG4Zca-fb4xJT9RqFBJ6rpPHSquBzLm7ldyQ,20227
139
+ openepd/model/versioning.py,sha256=wBZdOVL3ND9FMIRU9PS3vx9M_7MBiO70xYPQvPez6po,4522
140
+ openepd/patch_pydantic.py,sha256=bO7U5HqthFol0vfycb0a42UAGL3KOQ8-9MW4yCWOFP0,4150
141
141
  openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- openepd-6.14.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
143
- openepd-6.14.0.dist-info/METADATA,sha256=h-mIxr7O0iGai5O1phDjpdwakuWYzUtnrTzEW9BzX3U,9141
144
- openepd-6.14.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
145
- openepd-6.14.0.dist-info/RECORD,,
142
+ openepd-6.15.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
143
+ openepd-6.15.0.dist-info/METADATA,sha256=6kAg4ctCE4Zawd9nxaVsVRqKiHBWicl1NFgzKeSKNYo,9039
144
+ openepd-6.15.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
145
+ openepd-6.15.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 1.6.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any