openepd 7.2.0__py3-none-any.whl → 7.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
openepd/__version__.py CHANGED
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- VERSION = "7.2.0"
16
+ VERSION = "7.4.0"
openepd/bundle/base.py CHANGED
@@ -64,6 +64,46 @@ class BundleMixin:
64
64
  else:
65
65
  return asset_ref
66
66
 
67
+ @classmethod
68
+ def _asset_refs_to_str(cls, asset_refs: AssetRef | list[AssetRef] | None) -> list[str] | str | None:
69
+ """Convert single or multiple asset references to strings."""
70
+ if asset_refs is None:
71
+ return None
72
+ if isinstance(asset_refs, list):
73
+ return [cls._asset_ref_to_str(asset_ref) for asset_ref in asset_refs]
74
+ else:
75
+ return cls._asset_ref_to_str(asset_refs)
76
+
77
+ @classmethod
78
+ def _serialize_rel_asset_for_csv(cls, rel_asset: list[str] | str | None) -> str | None:
79
+ """
80
+ Serialize rel_asset for CSV storage.
81
+
82
+ Multiple assets are joined with semicolons.
83
+ """
84
+ if rel_asset is None:
85
+ return None
86
+ if isinstance(rel_asset, list):
87
+ # For empty list, return None. For non-empty list, join with semicolons
88
+ return ";".join(rel_asset) if rel_asset else None
89
+ else:
90
+ # Single asset - return as string
91
+ return str(rel_asset)
92
+
93
+ @classmethod
94
+ def _deserialize_rel_asset_from_csv(cls, rel_asset_str: str | None) -> list[str] | str | None:
95
+ """
96
+ Deserialize rel_asset from CSV storage.
97
+
98
+ Semicolon-separated values become lists.
99
+ """
100
+ if rel_asset_str is None or rel_asset_str == "":
101
+ return None
102
+ if ";" in rel_asset_str:
103
+ return rel_asset_str.split(";")
104
+ else:
105
+ return rel_asset_str
106
+
67
107
 
68
108
  class BaseBundleReader(BundleMixin, metaclass=abc.ABCMeta):
69
109
  """Base class for bundle readers."""
@@ -180,7 +220,7 @@ class BaseBundleWriter(BundleMixin, metaclass=abc.ABCMeta):
180
220
  self,
181
221
  data: IO[bytes],
182
222
  content_type: str | None,
183
- rel_asset: AssetRef | None = None,
223
+ rel_asset: AssetRef | list[AssetRef] | None = None,
184
224
  rel_type: str | None = None,
185
225
  file_name: str | None = None,
186
226
  name: str | None = None,
@@ -196,7 +236,7 @@ class BaseBundleWriter(BundleMixin, metaclass=abc.ABCMeta):
196
236
  def write_object_asset(
197
237
  self,
198
238
  obj: TOpenEpdObject,
199
- rel_asset: AssetRef | None = None,
239
+ rel_asset: AssetRef | list[AssetRef] | None = None,
200
240
  rel_type: str | None = None,
201
241
  file_name: str | None = None,
202
242
  name: str | None = None,
openepd/bundle/model.py CHANGED
@@ -80,6 +80,7 @@ class AssetInfo(BaseOpenEpdSchema):
80
80
  """The language of the asset."""
81
81
  rel_type: str | None
82
82
  rel_asset: str | None
83
+ """The related asset reference (serialized as semicolon-separated for multiple assets)."""
83
84
  comment: str | None = pydantic.Field(default=None)
84
85
  content_type: str | None = pydantic.Field(default=None)
85
86
  size: int | None = pydantic.Field(default=None)
openepd/bundle/reader.py CHANGED
@@ -61,8 +61,12 @@ class DefaultBundleReader(BaseBundleReader):
61
61
  return False
62
62
  if name is not None and a.name != name:
63
63
  return False
64
- if parent_ref is not None and a.rel_asset != parent_ref:
65
- return False
64
+ if parent_ref is not None:
65
+ parent_ref_str = self._asset_ref_to_str(parent_ref)
66
+ # Get the actual list of related assets
67
+ rel_asset_list = self._get_rel_asset_list(a)
68
+ if parent_ref_str not in rel_asset_list:
69
+ return False
66
70
  if ref_type is not None and a.rel_type != ref_type:
67
71
  return False
68
72
  if is_translated is not None and a.lang is not None and "translated" in a.lang:
@@ -85,6 +89,20 @@ class DefaultBundleReader(BaseBundleReader):
85
89
  input_dict[x] = None
86
90
  return input_dict
87
91
 
92
+ def _get_rel_asset_list(self, asset_info: AssetInfo) -> list[str]:
93
+ """Get the list of related asset references from an AssetInfo object."""
94
+ if asset_info.rel_asset is None:
95
+ return []
96
+
97
+ # Deserialize from CSV format (semicolon-separated values)
98
+ deserialized = self._deserialize_rel_asset_from_csv(asset_info.rel_asset)
99
+ if isinstance(deserialized, list):
100
+ return deserialized
101
+ elif isinstance(deserialized, str):
102
+ return [deserialized]
103
+ else:
104
+ return []
105
+
88
106
  def assets_iter(self) -> Iterator[AssetInfo]:
89
107
  """Iterate over all assets in the bundle."""
90
108
  with self._bundle_archive.open("toc", "r") as toc_stream:
@@ -132,7 +150,8 @@ class DefaultBundleReader(BaseBundleReader):
132
150
  rel_type = [rel_type]
133
151
  asset_ref = self._asset_ref_to_str(asset)
134
152
  for x in self.assets_iter():
135
- if x.rel_asset == asset_ref:
153
+ rel_asset_list = self._get_rel_asset_list(x)
154
+ if asset_ref in rel_asset_list:
136
155
  if rel_type is None or x.rel_type in rel_type:
137
156
  yield x
138
157
 
openepd/bundle/writer.py CHANGED
@@ -50,7 +50,7 @@ class DefaultBundleWriter(BaseBundleWriter):
50
50
  self,
51
51
  data: IO[bytes],
52
52
  content_type: str | None = None,
53
- rel_asset: AssetRef | None = None,
53
+ rel_asset: AssetRef | list[AssetRef] | None = None,
54
54
  rel_type: str | None = None,
55
55
  file_name: str | None = None,
56
56
  name: str | None = None,
@@ -60,7 +60,9 @@ class DefaultBundleWriter(BaseBundleWriter):
60
60
  custom_data: str | None = None,
61
61
  ) -> AssetInfo:
62
62
  """Write a blob asset to the bundle."""
63
- rel_ref_str = self._asset_ref_to_str(rel_asset) if rel_asset is not None else None
63
+ # Convert multiple rel_asset to proper format and serialize for storage
64
+ rel_ref_converted = self._asset_refs_to_str(rel_asset)
65
+ rel_ref_serialized = self._serialize_rel_asset_for_csv(rel_ref_converted)
64
66
  ref_str = self.__generate_entry_name(
65
67
  AssetType.Blob,
66
68
  self.__get_ext_for_content_type(content_type, "bin"),
@@ -72,7 +74,7 @@ class DefaultBundleWriter(BaseBundleWriter):
72
74
  type=AssetType.Blob,
73
75
  lang=lang,
74
76
  rel_type=rel_type,
75
- rel_asset=rel_ref_str,
77
+ rel_asset=rel_ref_serialized,
76
78
  content_type=content_type,
77
79
  comment=comment,
78
80
  custom_type=custom_type,
@@ -85,7 +87,7 @@ class DefaultBundleWriter(BaseBundleWriter):
85
87
  def write_object_asset(
86
88
  self,
87
89
  obj: TOpenEpdObject,
88
- rel_asset: AssetRef | None = None,
90
+ rel_asset: list[AssetRef] | AssetRef | None = None,
89
91
  rel_type: str | None = None,
90
92
  file_name: str | None = None,
91
93
  name: str | None = None,
@@ -100,7 +102,9 @@ class DefaultBundleWriter(BaseBundleWriter):
100
102
  msg = f"Object {obj} does not have a valid asset type and can't be written to a bundle."
101
103
  raise ValueError(msg)
102
104
  asset_type = AssetType(asset_type_str)
103
- rel_ref_str = self._asset_ref_to_str(rel_asset) if rel_asset is not None else None
105
+ # Convert multiple rel_asset to proper format and serialize for storage
106
+ rel_ref_converted = self._asset_refs_to_str(rel_asset)
107
+ rel_ref_serialized = self._serialize_rel_asset_for_csv(rel_ref_converted)
104
108
  ref_str = self.__generate_entry_name(
105
109
  asset_type,
106
110
  self.__get_ext_for_content_type("application/json", "json"),
@@ -111,7 +115,7 @@ class DefaultBundleWriter(BaseBundleWriter):
111
115
  name=name,
112
116
  type=asset_type,
113
117
  lang=lang,
114
- rel_asset=rel_ref_str,
118
+ rel_asset=rel_ref_serialized,
115
119
  rel_type=rel_type,
116
120
  content_type="application/json",
117
121
  comment=comment,
@@ -44,8 +44,6 @@ from openepd.model.specs.enums import (
44
44
  )
45
45
  from openepd.model.specs.range.mixins.access_flooring_mixin import AccessFlooringRangeMixin
46
46
 
47
- # NB! This is a generated code. Do not edit it manually. Please see src/openepd/model/specs/README.md
48
-
49
47
 
50
48
  class CementRangeV1(BaseOpenEpdHierarchicalSpec):
51
49
  """
@@ -181,17 +179,27 @@ class AccessFlooringPanelsRangeV1(BaseOpenEpdHierarchicalSpec, AccessFlooringRan
181
179
  _EXT_VERSION = "1.0"
182
180
 
183
181
 
182
+ class AsphaltInputsRangeV1(BaseOpenEpdHierarchicalSpec):
183
+ """
184
+ Binders, additives, and other non-aggregate-like ingredients for asphalt.
185
+
186
+ Range version.
187
+ """
188
+
189
+ _EXT_VERSION = "1.0"
190
+
191
+
184
192
  class ManufacturingInputsRangeV1(BaseOpenEpdHierarchicalSpec):
185
193
  """
186
194
  Manufacturing inputs.
187
195
 
188
196
  Broad category for collecting materials primarily used as manufacturing inputs, rather than directly used in
189
- a construction.
197
+ construction.
190
198
 
191
199
  Range version.
192
200
  """
193
201
 
194
- _EXT_VERSION = "1.1"
202
+ _EXT_VERSION = "1.2"
195
203
 
196
204
  AccessFlooringPedestals: AccessFlooringPedestalsRangeV1 | None = None
197
205
  CarpetBacking: CarpetBackingRangeV1 | None = None
@@ -200,3 +208,4 @@ class ManufacturingInputsRangeV1(BaseOpenEpdHierarchicalSpec):
200
208
  ConcreteAdmixtures: ConcreteAdmixturesRangeV1 | None = None
201
209
  Textiles: TextilesRangeV1 | None = None
202
210
  AccessFlooringPanels: AccessFlooringPanelsRangeV1 | None = None
211
+ AsphaltInputs: AsphaltInputsRangeV1 | None = None
@@ -64,8 +64,6 @@ from openepd.model.validation.quantity import (
64
64
  AmountRangeUFactor,
65
65
  )
66
66
 
67
- # NB! This is a generated code. Do not edit it manually. Please see src/openepd/model/specs/README.md
68
-
69
67
 
70
68
  class PanelDoorsRangeV1(BaseOpenEpdHierarchicalSpec):
71
69
  """
@@ -218,7 +216,15 @@ class UnitSkylightsRangeV1(BaseOpenEpdHierarchicalSpec):
218
216
  Range version.
219
217
  """
220
218
 
221
- _EXT_VERSION = "1.0"
219
+ _EXT_VERSION = "1.1"
220
+
221
+ roof_window: bool | None = pydantic.Field(
222
+ default=None,
223
+ description=(
224
+ "Similar to a skylight but has an outward opening that extends from a roof, and is therefore not fixed"
225
+ ),
226
+ examples=[True],
227
+ )
222
228
 
223
229
 
224
230
  class WindowsRangeV1(BaseOpenEpdHierarchicalSpec):
@@ -152,15 +152,21 @@ class AccessFlooringPanelsV1(BaseOpenEpdHierarchicalSpec, AccessFlooringMixin):
152
152
  _EXT_VERSION = "1.0"
153
153
 
154
154
 
155
+ class AsphaltInputsV1(BaseOpenEpdHierarchicalSpec):
156
+ """Binders, additives, and other non-aggregate-like ingredients for asphalt."""
157
+
158
+ _EXT_VERSION = "1.0"
159
+
160
+
155
161
  class ManufacturingInputsV1(BaseOpenEpdHierarchicalSpec):
156
162
  """
157
163
  Manufacturing inputs.
158
164
 
159
165
  Broad category for collecting materials primarily used as manufacturing inputs, rather than directly used in
160
- a construction.
166
+ construction.
161
167
  """
162
168
 
163
- _EXT_VERSION = "1.1"
169
+ _EXT_VERSION = "1.2"
164
170
 
165
171
  # Nested specs:
166
172
  AccessFlooringPedestals: AccessFlooringPedestalsV1 | None = None
@@ -170,3 +176,4 @@ class ManufacturingInputsV1(BaseOpenEpdHierarchicalSpec):
170
176
  ConcreteAdmixtures: ConcreteAdmixturesV1 | None = None
171
177
  Textiles: TextilesV1 | None = None
172
178
  AccessFlooringPanels: AccessFlooringPanelsV1 | None = None
179
+ AsphaltInputs: AsphaltInputsV1 | None = None
@@ -259,7 +259,15 @@ class UnitSkylightsV1(BaseOpenEpdHierarchicalSpec):
259
259
  by hand (cf. roof window). Includes frame(s) and possibly operating hardware.
260
260
  """
261
261
 
262
- _EXT_VERSION = "1.0"
262
+ _EXT_VERSION = "1.1"
263
+
264
+ roof_window: bool | None = pydantic.Field(
265
+ default=None,
266
+ description=(
267
+ "Similar to a skylight but has an outward opening that extends from a roof, and is therefore not fixed"
268
+ ),
269
+ examples=[True],
270
+ )
263
271
 
264
272
 
265
273
  class WindowsV1(BaseOpenEpdHierarchicalSpec):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openepd
3
- Version: 7.2.0
3
+ Version: 7.4.0
4
4
  Summary: Python library to work with OpenEPD format
5
5
  License: Apache-2.0
6
6
  Author: C-Change Labs
@@ -8,7 +8,7 @@ Author-email: support@c-change-labs.com
8
8
  Maintainer: C-Change Labs
9
9
  Maintainer-email: open-source@c-change-labs.com
10
10
  Requires-Python: >=3.11,<4.0
11
- Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: Apache Software License
14
14
  Classifier: Operating System :: OS Independent
@@ -20,7 +20,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
20
  Provides-Extra: api-client
21
21
  Requires-Dist: email-validator (>=1.3.1)
22
22
  Requires-Dist: idna (>=3.7)
23
- Requires-Dist: open-xpd-uuid (>=0.2.1,<0.3.0)
23
+ Requires-Dist: open-xpd-uuid (>=0.2.1,<2)
24
24
  Requires-Dist: openlocationcode (>=1.0.1)
25
25
  Requires-Dist: pydantic (>=2.0,<3)
26
26
  Requires-Dist: requests (>=2.0) ; extra == "api-client"
@@ -44,6 +44,24 @@ Description-Content-Type: text/markdown
44
44
 
45
45
  This library is a Python library to work with OpenEPD format.
46
46
 
47
+ > ⚠️ **Version Warning**
48
+ >
49
+ > This application is currently developed in **two major versions** in parallel:
50
+ >
51
+ > - **v6.x (>=6.0.0)** — Stable and production-ready. Maintains support for Pydantic v1 and v2 through a compatibility layer.
52
+ > - **v7.x (>=7.0.0)** — Public beta. Fully functional, with native support for Pydantic v2. Still experimental and may introduce breaking changes in **internal and integration interfaces**.
53
+ >
54
+ > ⚠️ No breaking changes are expected in the **public standard or data model**, only in internal APIs and integration points.
55
+ >
56
+ > Both versions currently offer the same set of features.
57
+ > We recommend using **v6** for most production use cases as the more mature and stable option.
58
+ > **v7** is suitable for production environments that can tolerate some level of interface instability and want to adopt the latest internals.
59
+ >
60
+ > 💡 Only the **latest version of v7** is guaranteed to contain all the features and updates from v6. Earlier v7 releases may lack some recent improvements.
61
+ >
62
+ > Once **v7 is promoted to stable**, all earlier **pre-stable (beta) v7 releases** will be **marked as yanked** to prevent accidental usage in production.
63
+ >
64
+
47
65
  ## About OpenEPD
48
66
 
49
67
  [openEPD](https://www.buildingtransparency.org/programs/openepd/) is an open data format for passing digital
@@ -63,13 +81,6 @@ documenting supply-chain specific data.
63
81
 
64
82
  ## Usage
65
83
 
66
- **❗ ATTENTION**: Pick the right version. The cornerstone of this library models package representing openEPD models.
67
- Models are defined with Pydantic library which is a dependency for openepd package. If you use Pydantic in your project
68
- carefully pick the version:
69
-
70
- * Use version **below** `2.0.0` if your project uses Pydantic version below `2.0.0`
71
- * Use version `2.x.x` or higher if your project uses Pydantic version `2.0.0` or above
72
-
73
84
  ### Models
74
85
 
75
86
  The library provides the Pydantic models for all the OpenEPD entities. The models are available in the `openepd.models`
@@ -1,5 +1,5 @@
1
1
  openepd/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
2
- openepd/__version__.py,sha256=_5NJwIJ7J9H-KhVx7TGryTwScUPd5wpsdLOYvKyssyU,638
2
+ openepd/__version__.py,sha256=1XUGGHndMgV1s_izfZdyfLJPpht1-cxMXpkenDHeldQ,638
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
5
  openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=mjTT8eGtfj6Fgp-wcs0cCWA7DJo1KL_iQ75rgKkaY3c,8037
@@ -31,10 +31,10 @@ openepd/api/sync_client.py,sha256=DiDSQU0kBd9gU17KrPUvo07pyLv15rGozuWXbkM1JzA,40
31
31
  openepd/api/test/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
32
32
  openepd/api/utils.py,sha256=xOU8ihC0eghsoaCFhC85PU4WYRwNxVEpfK3gzq4e9ik,2092
33
33
  openepd/bundle/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
34
- openepd/bundle/base.py,sha256=ovURf721k9XWe0C8-tmik_bEOrHdOtF1jbN03T5G7M4,6918
35
- openepd/bundle/model.py,sha256=bO6GAN_hMmpnYn9LQAHl6bw9cqwphlZZtMCkQZHzP8c,2627
36
- openepd/bundle/reader.py,sha256=9gmcfwzWTUukVtUJbIsJG-Nxumsf1e4wEKCSwmtLLJ4,6936
37
- openepd/bundle/writer.py,sha256=nfzpkHqY3jX0x7GGsWMts-9x1vJhjETfnL6lnDAqqJQ,8392
34
+ openepd/bundle/base.py,sha256=2tv7KbxG9zC_nuMOGudorxZcTl5rU6ABJmEbO2WTPas,8400
35
+ openepd/bundle/model.py,sha256=4pmOCgK-kdBu7_PLm5QhlrVZRmab_18o0EGvcUjI8FQ,2722
36
+ openepd/bundle/reader.py,sha256=H1mfuFxV2G0q9ld0dJ6SRucTwcTSEi-sFoKJLsBk4IQ,7767
37
+ openepd/bundle/writer.py,sha256=cyFikYTtZCcX0rhdpbuvOaOBG4CS1nE8JjHUdB7Wghs,8708
38
38
  openepd/m49/__init__.py,sha256=AApOMp9PJPMXZbPB4piedqKtgHE01mlj_MyF3kf519U,718
39
39
  openepd/m49/const.py,sha256=bkYu6J7dQNVb2-nNkjy97uMpt64vICX5o-PHr0lk_90,31833
40
40
  openepd/m49/utils.py,sha256=vQl0wMXtYS2b7NeLIWilDNUopq3MATmLnhEFcMYTeZA,7256
@@ -76,7 +76,7 @@ openepd/model/specs/range/finishes.py,sha256=1CmI0nQtN7AumrahtPBy9IAYd_o-ljiXWoc
76
76
  openepd/model/specs/range/fire_and_smoke_protection.py,sha256=5OXhDlPiWQ4AWu9tDuQ1AkpcCnd9rfP9c1GRsOhBSyA,3333
77
77
  openepd/model/specs/range/furnishings.py,sha256=j-uNj2E5GNX-sgSgqSUcp6DosyuYOa36EBNIdIQ7F80,6748
78
78
  openepd/model/specs/range/grouting.py,sha256=BQPxH6BvlXpdhLEZBui9zTuY93K_9syjoa6rdnF8GGY,1095
79
- openepd/model/specs/range/manufacturing_inputs.py,sha256=4HzcvNwwfwQKcZKB-seZSaCDpuSeDzci1mWA2P_DQM8,6027
79
+ openepd/model/specs/range/manufacturing_inputs.py,sha256=NoZh49G5Mpnzv3KLK_lUNgh85svr59oGW27NDGTCJno,6175
80
80
  openepd/model/specs/range/masonry.py,sha256=KQHdHx8cqE8e5KakNM0Ajn8pKmHVUpSdyc4MfMXUKIc,2908
81
81
  openepd/model/specs/range/material_handling.py,sha256=9jxRHpjMKu71B5omH55UjkNVJvaTLgTMtEidSKPFn5c,1483
82
82
  openepd/model/specs/range/mechanical.py,sha256=is6R3PpY0W8L1IQS-esDDnHPCls8J8KUpOESNZMxYsY,10463
@@ -84,7 +84,7 @@ openepd/model/specs/range/mechanical_insulation.py,sha256=eBvNMuW-zZyphay9aKOphw
84
84
  openepd/model/specs/range/mixins/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
85
85
  openepd/model/specs/range/mixins/access_flooring_mixin.py,sha256=pQH7lt7oD3e8g19-_4DEo8xmVU4pnpT-XKQbCwygmbc,2366
86
86
  openepd/model/specs/range/network_infrastructure.py,sha256=nq8g1s7_EKjZNODxnlfMB7ipZ90z5w7TVd6b5EUywkA,8738
87
- openepd/model/specs/range/openings.py,sha256=LvpKH1RynTkmuNm4A_ycCLuxuovMtGxggX5b-vz5BUY,15587
87
+ openepd/model/specs/range/openings.py,sha256=j7c49jlvfvnu03KVvYiNyyWEAjQYcxW6czxgD1z93Rw,15734
88
88
  openepd/model/specs/range/other_electrical_equipment.py,sha256=H4tZHcHyR2uUYHn-bQfLC6hR4tynVp_7EJbiI-YpK7Y,1001
89
89
  openepd/model/specs/range/other_materials.py,sha256=RHusAyExYl9n1BDiOFDq2_znEn3MXGxEkunb3BjiC2U,4495
90
90
  openepd/model/specs/range/plumbing.py,sha256=pjdIOvQAat-8e0zqJM7gs30h131mqryU5uCGOdeTRaE,5382
@@ -118,7 +118,7 @@ openepd/model/specs/singular/finishes.py,sha256=To1eHyvgJJTTOCNHXGpX27hMPrnMOcuh
118
118
  openepd/model/specs/singular/fire_and_smoke_protection.py,sha256=h8Dy4ps_xfa5g8EQEIN8OHxjH6aDvqmZUFRdEzYy7aY,3081
119
119
  openepd/model/specs/singular/furnishings.py,sha256=-8_96GZala4_xuI6u29OO0KfGA0OctsD3M5Iid2NHvE,5737
120
120
  openepd/model/specs/singular/grouting.py,sha256=pg2tX3W7a2TQ3z_eyFYGlBJY3WEwn6JlZyqM3PQIJcU,934
121
- openepd/model/specs/singular/manufacturing_inputs.py,sha256=JQnyrSRLpP0Ew-d2ieYS-yzlh55PWm5OYbZlWzsdq24,5628
121
+ openepd/model/specs/singular/manufacturing_inputs.py,sha256=9dVt_jZUUZa8ISEtBlmjTFuYte1jMUHCl1utz-sjTbw,5839
122
122
  openepd/model/specs/singular/masonry.py,sha256=e9siblrPFFSvIjucYkwZzSlpSSZPZ9rA1bdVIDQz-RM,3627
123
123
  openepd/model/specs/singular/material_handling.py,sha256=iEeUx1hNKla669y0zl-QAJn6xA7ceq75aRG8qT0p56Q,1274
124
124
  openepd/model/specs/singular/mechanical.py,sha256=q-89Ch0uTlEqFRXM5QPgkmf23L-xyCzVK_mQ33pU4UA,10191
@@ -127,7 +127,7 @@ openepd/model/specs/singular/mixins/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_s
127
127
  openepd/model/specs/singular/mixins/access_flooring_mixin.py,sha256=gM5H6lTjj2eytYnzt-4PaJ_dc8wNH_gJzBazJb83j5E,3083
128
128
  openepd/model/specs/singular/mixins/conduit_mixin.py,sha256=H5rbXIy3lpiU_Rub3_f7cECtQE2odu1-nIKuRjtO6ts,1959
129
129
  openepd/model/specs/singular/network_infrastructure.py,sha256=QGMIFzexHH94phkFw7iYl-fTZ_514dwYgvC-2sHjOZw,9316
130
- openepd/model/specs/singular/openings.py,sha256=fcYBvSJW64fBArvs0ajcRXRegE07p-YmURICmLA8ilY,19544
130
+ openepd/model/specs/singular/openings.py,sha256=8XI9W-4h9oK1_hWNVOzNwvWxIZdAEze0A8ach5hThSU,19794
131
131
  openepd/model/specs/singular/other_electrical_equipment.py,sha256=FX7p4rMuUbTrz1yDwKkS-Z6odohoq-zCw6SU3Kw5ISs,814
132
132
  openepd/model/specs/singular/other_materials.py,sha256=_00_fCPn7G_-HVKC1cQcNvBDf4CtXFLOGvYLDJtL5ZA,3498
133
133
  openepd/model/specs/singular/plumbing.py,sha256=dP6r7xy2yeP8ICEBN79CfJqyDiuwpTtDnURBfWmFWPs,4639
@@ -146,7 +146,7 @@ openepd/model/validation/numbers.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9
146
146
  openepd/model/validation/quantity.py,sha256=M9dz3byTK6Lrys43I0Gq7n2b0aE8WYys-idxi6bKCII,21755
147
147
  openepd/model/versioning.py,sha256=LldrNjPjVBsVTWyJrBe6VoI19B0d47QXbHk_6omXPxc,4561
148
148
  openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
149
- openepd-7.2.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
150
- openepd-7.2.0.dist-info/METADATA,sha256=ApO7NYw6zL9cNkbOPtnwL_qQn4p7cg0pD3mSWkgYPvg,9063
151
- openepd-7.2.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
152
- openepd-7.2.0.dist-info/RECORD,,
149
+ openepd-7.4.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
150
+ openepd-7.4.0.dist-info/METADATA,sha256=n2TgNI22H2gDPgDHUjABMMFxTvQuqhwN0XyHeVHbNs8,9810
151
+ openepd-7.4.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
152
+ openepd-7.4.0.dist-info/RECORD,,