openepd 4.10.0__py3-none-any.whl → 4.11.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 = "4.10.0"
16
+ VERSION = "4.11.0"
@@ -0,0 +1,15 @@
1
+ #
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
@@ -0,0 +1,200 @@
1
+ #
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from typing import Literal, TypeAlias, overload
17
+
18
+ from requests import Response
19
+
20
+ from openepd.api.base_sync_client import BaseApiMethodGroup
21
+ from openepd.api.common import StreamingListResponse, paging_meta_from_v1_api
22
+ from openepd.api.dto.common import BaseMeta, OpenEpdApiResponse
23
+ from openepd.api.dto.meta import PagingMetaMixin
24
+ from openepd.api.utils import encode_path_param
25
+ from openepd.model.generic_estimate import (
26
+ GenericEstimate,
27
+ GenericEstimatePreview,
28
+ GenericEstimateRef,
29
+ GenericEstimateWithDeps,
30
+ )
31
+
32
+
33
+ class GenericEstimateApi(BaseApiMethodGroup):
34
+ """API methods for Generic Estimates."""
35
+
36
+ @overload
37
+ def get_by_open_xpd_uuid(self, uuid: str, with_response: Literal[True]) -> tuple[GenericEstimate, Response]: ...
38
+
39
+ @overload
40
+ def get_by_open_xpd_uuid(self, uuid: str, with_response: Literal[False] = False) -> GenericEstimate: ...
41
+
42
+ def get_by_open_xpd_uuid(
43
+ self, uuid: str, with_response: bool = False
44
+ ) -> GenericEstimate | tuple[GenericEstimate, Response]:
45
+ """
46
+ Get Generic Estimate by OpenEPD UUID.
47
+
48
+ :param uuid: Open xPD UUID
49
+ :param with_response: whether to return just object or with response
50
+ :return: GE or GE with response depending on param with_response
51
+ :raise ObjectNotFound: if Generic Estimate is not found
52
+ """
53
+ response = self._client.do_request("get", f"/generic_estimates/{uuid}")
54
+ if with_response:
55
+ return GenericEstimate.parse_obj(response.json()), response
56
+ return GenericEstimate.parse_obj(response.json())
57
+
58
+ @overload
59
+ def post_with_refs(
60
+ self, ge: GenericEstimateWithDeps, with_response: Literal[True]
61
+ ) -> tuple[GenericEstimate, Response]: ...
62
+
63
+ @overload
64
+ def post_with_refs(self, ge: GenericEstimateWithDeps, with_response: Literal[False] = False) -> GenericEstimate: ...
65
+
66
+ def post_with_refs(
67
+ self, ge: GenericEstimateWithDeps, with_response: bool = False
68
+ ) -> GenericEstimate | tuple[GenericEstimate, Response]:
69
+ """
70
+ Post an GenericEstimate with references.
71
+
72
+ :param ge: GenericEstimate
73
+ :param with_response: return the response object togather with the GenericEstimate
74
+ :return: GenericEstimate alone, or GenericEstimate with HTTP Response object depending on parameter
75
+ """
76
+ response = self._client.do_request(
77
+ "patch",
78
+ "/generic_estimates/post_with_refs",
79
+ json=ge.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
80
+ )
81
+ content = response.json()
82
+ if with_response:
83
+ return GenericEstimate.parse_obj(content), response
84
+ return GenericEstimate.parse_obj(content)
85
+
86
+ @overload
87
+ def create(self, ge: GenericEstimate, with_response: Literal[True]) -> tuple[GenericEstimateRef, Response]: ...
88
+
89
+ @overload
90
+ def create(self, ge: GenericEstimate, with_response: Literal[False] = False) -> GenericEstimateRef: ...
91
+
92
+ def create(
93
+ self, ge: GenericEstimate, with_response: bool = False
94
+ ) -> GenericEstimateRef | tuple[GenericEstimateRef, Response]:
95
+ """
96
+ Create a Generic Estimate.
97
+
98
+ :param ge: Generic Estimate
99
+ :param with_response: return the response object together with the EPD
100
+ :return: Generic Estimate or Generic Estimate with HTTP Response object depending on parameter
101
+ """
102
+ response = self._client.do_request(
103
+ "post",
104
+ "/generic_estimates",
105
+ json=ge.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
106
+ )
107
+ content = response.json()
108
+ if with_response:
109
+ return GenericEstimateRef.parse_obj(content), response
110
+ return GenericEstimateRef.parse_obj(content)
111
+
112
+ @overload
113
+ def edit(self, ge: GenericEstimate, with_response: Literal[True]) -> tuple[GenericEstimateRef, Response]: ...
114
+
115
+ @overload
116
+ def edit(self, ge: GenericEstimate, with_response: Literal[False] = False) -> GenericEstimateRef: ...
117
+
118
+ def edit(
119
+ self, ge: GenericEstimate, with_response: bool = False
120
+ ) -> GenericEstimateRef | tuple[GenericEstimateRef, Response]:
121
+ """
122
+ Edit a Generic Estimate.
123
+
124
+ :param ge: GenericEstimate
125
+ :param with_response: return the response object together with the GE
126
+ :return: GE or GE with HTTP Response object depending on parameter
127
+ """
128
+ ge_id = ge.id
129
+ if not ge_id:
130
+ raise ValueError("The ID must be set to edit a GenericEstimate.")
131
+
132
+ response = self._client.do_request(
133
+ "put",
134
+ f"/generic_estimates/{encode_path_param(ge_id)}",
135
+ json=ge.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
136
+ )
137
+ content = response.json()
138
+ if with_response:
139
+ return GenericEstimateRef.parse_obj(content), response
140
+ return GenericEstimateRef.parse_obj(content)
141
+
142
+ @overload
143
+ def list_raw(
144
+ self, page_num: int, page_size: int, with_response: Literal[False] = False
145
+ ) -> list[GenericEstimatePreview]: ...
146
+
147
+ @overload
148
+ def list_raw(
149
+ self, page_num: int, page_size: int, with_response: Literal[True]
150
+ ) -> tuple[list[GenericEstimatePreview], Response]: ...
151
+
152
+ def list_raw(
153
+ self, page_num: int = 1, page_size: int = 10, with_response: bool = False
154
+ ) -> list[GenericEstimatePreview] | tuple[list[GenericEstimatePreview], Response]:
155
+ """
156
+ List generic estimates.
157
+
158
+ :param page_num: page number
159
+ :param page_size: page size
160
+ :param with_response: whether to return just object or with response
161
+
162
+ :return: GE or GE with HTTP Response object depending on parameter
163
+ """
164
+ response = self._client.do_request(
165
+ "get",
166
+ "/generic_estimates",
167
+ params=dict(
168
+ page_number=page_num,
169
+ page_size=page_size,
170
+ ),
171
+ )
172
+ data = [GenericEstimatePreview.parse_obj(o) for o in response.json()]
173
+ if with_response:
174
+ return data, response
175
+ return data
176
+
177
+ def list(self, page_size: int | None = None) -> StreamingListResponse[GenericEstimatePreview]:
178
+ """
179
+ List GenericEstimates.
180
+
181
+ :param page_size: page size, None for default
182
+ :return: streaming list of GEs
183
+ """
184
+
185
+ def _get_page(p_num: int, p_size: int) -> GenericEstimateListResponse:
186
+ data_list, response = self.list_raw(page_num=p_num, page_size=p_size, with_response=True)
187
+ return GenericEstimateListResponse(
188
+ payload=data_list, meta=GenericEstimateSearchMeta(paging=paging_meta_from_v1_api(response))
189
+ )
190
+
191
+ return StreamingListResponse[GenericEstimatePreview](_get_page, page_size=page_size)
192
+
193
+
194
+ class GenericEstimateSearchMeta(PagingMetaMixin, BaseMeta):
195
+ """Metadata for EPD Search endpoint."""
196
+
197
+ pass
198
+
199
+
200
+ GenericEstimateListResponse: TypeAlias = OpenEpdApiResponse[list[GenericEstimatePreview], GenericEstimateSearchMeta]
@@ -0,0 +1,164 @@
1
+ #
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ from typing import Literal, TypeAlias, overload
17
+
18
+ from requests import Response
19
+
20
+ from openepd.api.base_sync_client import BaseApiMethodGroup
21
+ from openepd.api.common import StreamingListResponse, paging_meta_from_v1_api
22
+ from openepd.api.dto.common import BaseMeta, OpenEpdApiResponse
23
+ from openepd.api.dto.meta import PagingMetaMixin
24
+ from openepd.api.utils import encode_path_param
25
+ from openepd.model.industry_epd import IndustryEpd, IndustryEpdPreview, IndustryEpdRef
26
+
27
+
28
+ class IndustryEpdApi(BaseApiMethodGroup):
29
+ """API methods for Industry EPD."""
30
+
31
+ @overload
32
+ def get_by_open_xpd_uuid(self, uuid: str, with_response: Literal[True]) -> tuple[IndustryEpd, Response]: ...
33
+
34
+ @overload
35
+ def get_by_open_xpd_uuid(self, uuid: str, with_response: Literal[False] = False) -> IndustryEpd: ...
36
+
37
+ def get_by_open_xpd_uuid(
38
+ self, uuid: str, with_response: bool = False
39
+ ) -> IndustryEpd | tuple[IndustryEpd, Response]:
40
+ """
41
+ Get Industry EPD by OpenEPD UUID.
42
+
43
+ :param uuid: OpenEPD UUID
44
+ :param with_response: whether to return just object or with response
45
+ :return: IEPD or IEPD with response depending on param with_response
46
+ :raise ObjectNotFound: if Industry EPD is not found
47
+ """
48
+ response = self._client.do_request("get", f"/industry_epds/{uuid}")
49
+ if with_response:
50
+ return IndustryEpd.parse_obj(response.json()), response
51
+ return IndustryEpd.parse_obj(response.json())
52
+
53
+ @overload
54
+ def create(self, iepd: IndustryEpd, with_response: Literal[True]) -> tuple[IndustryEpdRef, Response]: ...
55
+
56
+ @overload
57
+ def create(self, iepd: IndustryEpd, with_response: Literal[False] = False) -> IndustryEpdRef: ...
58
+
59
+ def create(
60
+ self, iepd: IndustryEpd, with_response: bool = False
61
+ ) -> IndustryEpdRef | tuple[IndustryEpdRef, Response]:
62
+ """
63
+ Create an Industry EPD.
64
+
65
+ :param iepd: Industry EPD
66
+ :param with_response: return the response object together with the EPD
67
+ :return: Industry EPD or Industry EPD with HTTP Response object depending on parameter
68
+ """
69
+ response = self._client.do_request(
70
+ "post",
71
+ "/industry_epds",
72
+ json=iepd.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
73
+ )
74
+ content = response.json()
75
+ if with_response:
76
+ return IndustryEpdRef.parse_obj(content), response
77
+ return IndustryEpdRef.parse_obj(content)
78
+
79
+ @overload
80
+ def edit(self, iepd: IndustryEpd, with_response: Literal[True]) -> tuple[IndustryEpdRef, Response]: ...
81
+
82
+ @overload
83
+ def edit(self, iepd: IndustryEpd, with_response: Literal[False] = False) -> IndustryEpdRef: ...
84
+
85
+ def edit(self, iepd: IndustryEpd, with_response: bool = False) -> IndustryEpdRef | tuple[IndustryEpdRef, Response]:
86
+ """
87
+ Edit an Industr EPD.
88
+
89
+ :param iepd: IndustryEpd
90
+ :param with_response: return the response object together with the IEPD
91
+ :return: IEPD or IEPD with HTTP Response object depending on parameter
92
+ """
93
+ iepd_id = iepd.id
94
+ if not iepd_id:
95
+ raise ValueError("The ID must be set to edit a IndustryEpd.")
96
+
97
+ response = self._client.do_request(
98
+ "put",
99
+ f"/industry_epds/{encode_path_param(iepd_id)}",
100
+ json=iepd.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
101
+ )
102
+ content = response.json()
103
+ if with_response:
104
+ return IndustryEpdRef.parse_obj(content), response
105
+ return IndustryEpdRef.parse_obj(content)
106
+
107
+ @overload
108
+ def list_raw(
109
+ self, page_num: int, page_size: int, with_response: Literal[False] = False
110
+ ) -> list[IndustryEpdPreview]: ...
111
+
112
+ @overload
113
+ def list_raw(
114
+ self, page_num: int, page_size: int, with_response: Literal[True]
115
+ ) -> tuple[list[IndustryEpdPreview], Response]: ...
116
+
117
+ def list_raw(
118
+ self, page_num: int = 1, page_size: int = 10, with_response: bool = False
119
+ ) -> list[IndustryEpdPreview] | tuple[list[IndustryEpdPreview], Response]:
120
+ """
121
+ List industry epds.
122
+
123
+ :param page_num: page number
124
+ :param page_size: page size
125
+ :param with_response: whether to return just object or with response
126
+ :return: list of IEPDs or list of IEPDs with response depending on param with_response
127
+ """
128
+ response = self._client.do_request(
129
+ "get",
130
+ "/industry_epds",
131
+ params=dict(
132
+ page_number=page_num,
133
+ page_size=page_size,
134
+ ),
135
+ )
136
+ data = [IndustryEpdPreview.parse_obj(o) for o in response.json()]
137
+ if with_response:
138
+ return data, response
139
+ return data
140
+
141
+ def list(self, page_size: int | None = None) -> StreamingListResponse[IndustryEpdPreview]:
142
+ """
143
+ List IndustryEpds.
144
+
145
+ :param page_size: page size, None for default
146
+ :return: streaming list of IEPDs
147
+ """
148
+
149
+ def _get_page(p_num: int, p_size: int) -> IndustryEpdListResponse:
150
+ data_list, response = self.list_raw(page_num=p_num, page_size=p_size, with_response=True)
151
+ return IndustryEpdListResponse(
152
+ payload=data_list, meta=IndustryEpdSearchMeta(paging=paging_meta_from_v1_api(response))
153
+ )
154
+
155
+ return StreamingListResponse[IndustryEpdPreview](_get_page, page_size=page_size)
156
+
157
+
158
+ class IndustryEpdSearchMeta(PagingMetaMixin, BaseMeta):
159
+ """Metadata for EPD Search endpoint."""
160
+
161
+ pass
162
+
163
+
164
+ IndustryEpdListResponse: TypeAlias = OpenEpdApiResponse[list[IndustryEpdPreview], IndustryEpdSearchMeta]
openepd/api/common.py CHANGED
@@ -20,6 +20,8 @@ import threading
20
20
  from time import sleep
21
21
  from typing import Callable, Generic, Iterator, cast
22
22
 
23
+ from requests import Response
24
+
23
25
  from openepd.api.dto.common import DEFAULT_PAGE_SIZE, MetaCollectionDto, OpenEpdApiResponse
24
26
  from openepd.api.dto.meta import PagingMeta, PagingMetaMixin
25
27
  from openepd.model.base import TOpenEpdObject
@@ -233,3 +235,12 @@ def no_trailing_slash(val: str) -> str:
233
235
  while val.endswith("/"):
234
236
  val = val[:-1]
235
237
  return val
238
+
239
+
240
+ def paging_meta_from_v1_api(r: Response) -> PagingMeta:
241
+ """Return a PagingMeta dto from v1 API format with data in headers."""
242
+ return PagingMeta(
243
+ total_count=int(r.headers["X-Total-Count"]),
244
+ total_pages=int(r.headers["X-Total-Pages"]),
245
+ page_size=int(r.headers["X-Page-Size"]),
246
+ )
@@ -17,6 +17,8 @@ __all__ = ("OpenEpdApiClientSync",)
17
17
 
18
18
  from requests.auth import AuthBase
19
19
 
20
+ from openepd.api.average_dataset.generic_estimate_sync_api import GenericEstimateApi
21
+ from openepd.api.average_dataset.industry_epd_sync_api import IndustryEpdApi
20
22
  from openepd.api.base_sync_client import SyncHttpClient, TokenAuth
21
23
  from openepd.api.category.sync_api import CategoryApi
22
24
  from openepd.api.epd.sync_api import EpdApi
@@ -40,6 +42,8 @@ class OpenEpdApiClientSync:
40
42
  self.__epd_api: EpdApi | None = None
41
43
  self.__pcr_api: PcrApi | None = None
42
44
  self.__category_api: CategoryApi | None = None
45
+ self.__generic_estimate_api: GenericEstimateApi | None = None
46
+ self.__industry_epd_api: IndustryEpdApi | None = None
43
47
 
44
48
  @property
45
49
  def epds(self) -> EpdApi:
@@ -61,3 +65,17 @@ class OpenEpdApiClientSync:
61
65
  if self.__category_api is None:
62
66
  self.__category_api = CategoryApi(self._http_client)
63
67
  return self.__category_api
68
+
69
+ @property
70
+ def industry_epds(self) -> IndustryEpdApi:
71
+ """Get the Category API."""
72
+ if self.__industry_epd_api is None:
73
+ self.__industry_epd_api = IndustryEpdApi(self._http_client)
74
+ return self.__industry_epd_api
75
+
76
+ @property
77
+ def generic_estimates(self) -> GenericEstimateApi:
78
+ """Get the GE API."""
79
+ if self.__generic_estimate_api is None:
80
+ self.__generic_estimate_api = GenericEstimateApi(self._http_client)
81
+ return self.__generic_estimate_api
@@ -57,7 +57,7 @@ class BaseDeclaration(RootDocument, abc.ABC):
57
57
  kg_per_declared_unit: Amount | None = pyd.Field(
58
58
  default=None,
59
59
  description="Mass of the product, in kilograms, per declared unit",
60
- example=Amount(qty=12.5, unit="kg"),
60
+ example=Amount(qty=12.5, unit="kg").to_serializable(exclude_unset=True),
61
61
  )
62
62
  compliance: list[Standard] = pyd.Field(
63
63
  description="Standard(s) to which this document is compliant.", default_factory=list
@@ -129,7 +129,8 @@ class AverageDatasetMixin(pyd.BaseModel, title="Average Dataset"):
129
129
  )
130
130
 
131
131
  geography: list[Geography] | None = pyd.Field(
132
- "Jurisdiction(s) in which the LCA result is applicable. An empty array, or absent properties, implies global applicability."
132
+ description="Jurisdiction(s) in which the LCA result is applicable. An empty array, or absent properties, "
133
+ "implies global applicability.",
133
134
  )
134
135
 
135
136
 
@@ -58,6 +58,8 @@ class GenericEstimatePreviewV0(
58
58
  Excludes LCIA data.
59
59
  """
60
60
 
61
+ _FORMAT_VERSION = OpenEpdVersions.Version0.as_str()
62
+
61
63
  doctype: str = pyd.Field(
62
64
  description='Describes the type and schema of the document. Must always be "openGenericEstimate"',
63
65
  default="openGenericEstimate",
@@ -79,15 +81,7 @@ GenericEstimatePreview = GenericEstimatePreviewV0
79
81
 
80
82
 
81
83
  class GenericEstimateV0(GenericEstimatePreviewV0, WithLciaMixin, WithAltIdsMixin, title="Generic Estimate (Full)"):
82
- """
83
- Full Generic Estimate object.
84
-
85
- This is considered the most complete valid openEPD object for GenericEstimate. In addition to it, several related
86
- models are defined, either with fewer fields (to be used in APIs for list requests) or with more relaxed structure
87
- to support related entities matching.
88
- """
89
-
90
- _FORMAT_VERSION = OpenEpdVersions.Version0.as_str()
84
+ """Full Generic Estimate object."""
91
85
 
92
86
 
93
87
  GenericEstimate = GenericEstimateV0
@@ -98,10 +92,6 @@ class GenericEstimateWithDepsV0(GenericEstimateV0, title="Generic Estimate (with
98
92
  Expanded version of the GenericEstimate.
99
93
 
100
94
  Contains related entities - orgs - with full fields, to support object matching in implementations.
101
-
102
- For now the implementation matches the above GenericEstimate entity, but they will diverge as normal GE would have
103
- some required fields in Org (like web_domain), and WithDeps would not.
104
-
105
95
  """
106
96
 
107
97
  publisher: Org | None = pyd.Field(description="Organization that published the LCA results.")
@@ -279,7 +279,7 @@ class Geography(StrEnum):
279
279
  * ZM: Zambia
280
280
  * ZW: Zimbabwe
281
281
 
282
- USA states and Canada provinces, see https://en.wikipedia.org/wiki/ISO_3166-1:
282
+ USA and Canada subdivisions, see https://en.wikipedia.org/wiki/ISO_3166-1:
283
283
 
284
284
  * CA-AB: Alberta, Canada
285
285
  * CA-BC: British Columbia, Canada
@@ -49,6 +49,8 @@ class IndustryEpdPreviewV0(
49
49
  Used in lists and other cases where full LCIA data is not required.
50
50
  """
51
51
 
52
+ _FORMAT_VERSION = OpenEpdVersions.Version0.as_str()
53
+
52
54
  doctype: str = pyd.Field(
53
55
  description='Describes the type and schema of the document. Must always be "openIndustryEpd"',
54
56
  default="openIndustryEpd",
@@ -70,8 +72,6 @@ class IndustryEpdV0(IndustryEpdPreviewV0, WithLciaMixin, WithAltIdsMixin, title=
70
72
  to support related entities matching.
71
73
  """
72
74
 
73
- _FORMAT_VERSION = OpenEpdVersions.Version0.as_str()
74
-
75
75
 
76
76
  IndustryEpd = IndustryEpdV0
77
77
 
openepd/model/lcia.py CHANGED
@@ -322,6 +322,16 @@ class LCIAMethod(StrEnum):
322
322
  class Impacts(pyd.BaseModel):
323
323
  """List of environmental impacts, compiled per one of the standard Impact Assessment methods."""
324
324
 
325
+ class Config:
326
+ # pydantic schema generator gets lost in this structure, so we need to re-establish it manually for openapi
327
+ schema_extra = {
328
+ "properties": {
329
+ str(lm): {"description": str(lm), "allOf": [{"$ref": "#/components/schemas/ImpactSet"}]}
330
+ for lm in LCIAMethod
331
+ },
332
+ "additionalProperties": None,
333
+ }
334
+
325
335
  __root__: dict[LCIAMethod, ImpactSet]
326
336
 
327
337
  def set_unknown_lcia(self, impact_set: ImpactSet):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 4.10.0
3
+ Version: 4.11.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
@@ -164,6 +164,11 @@ The geography and country enums are generated from several sources, including py
164
164
  codes, UN m49 codification, and special regions. To update the enums, first update any of these sources, then use
165
165
  `make codegen`. See 'tools/openepd/codegen' for details.
166
166
 
167
+ ## Development
168
+
169
+ Windows is not supported for development. You can use WSL2 with Ubuntu 20.04 or higher.
170
+ Instructions are the same as for regular GNU/Linux installation.
171
+
167
172
  # Credits
168
173
 
169
174
  This library has been written and maintained by [C-Change Labs](https://c-change-labs.com/).
@@ -1,11 +1,14 @@
1
1
  openepd/__init__.py,sha256=Shkfh0Kun0YRhmRDw7LkUj2eQL3X-HnP55u2THOEALw,794
2
- openepd/__version__.py,sha256=v1iT7lM1VsfdI_pF-s9H_ZXF4x586x50rlNgWCMNKuA,639
2
+ openepd/__version__.py,sha256=qwTU6-8wWZPRnIWNUd5uUJ78I_K2fFTlOL1EfHKMhh0,639
3
3
  openepd/api/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
4
+ openepd/api/average_dataset/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
5
+ openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=FwzsUSJvbiaMIMfBXqI4b4W6sAS9TovKpD6jz8OzTKU,7693
6
+ openepd/api/average_dataset/industry_epd_sync_api.py,sha256=UOH2WGSqXKikbAKbofHMx28rXiy6D-GIXa7X-c7Bzsg,6303
4
7
  openepd/api/base_sync_client.py,sha256=jviqtQgsOVdRq5x7_Yh_Tg8zIdWtVTIUqNCgebf6YDg,20925
5
8
  openepd/api/category/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
6
9
  openepd/api/category/dto.py,sha256=tDojagSwT7CTtcYq31Qe_c0P3xKKUWXKdzT5iN6odtk,850
7
10
  openepd/api/category/sync_api.py,sha256=VHHOVbblZGyc4AtbsgQza00trSLuaCO6KfQw6r8vzgg,1371
8
- openepd/api/common.py,sha256=VVjeYbj5cEvPJJj1HtkvGrKHjeyuE71VHtbblZFjAO0,8464
11
+ openepd/api/common.py,sha256=LVYNs4AP-YnUB6eUqvpdcYttE6sMvuQJi4TA3aH0UPs,8812
9
12
  openepd/api/dto/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
10
13
  openepd/api/dto/base.py,sha256=dy-P2rIvYLMRTJaFeL6ayIUdvMW12sw4IafiEtHdyzs,1033
11
14
  openepd/api/dto/common.py,sha256=Msbh5fJf9s2mopxBLCko6jBJYxNq_0huz8q3hUOdDnw,4488
@@ -18,7 +21,7 @@ openepd/api/epd/sync_api.py,sha256=5wuPiM_zVciVtTvsGaaRdf7T6q2CUp7QMZCW0DAjQng,7
18
21
  openepd/api/errors.py,sha256=Pcg2JqjLoUXUFJTVdIFbd8rgjGoAT5HpnivTpFRACVU,2159
19
22
  openepd/api/pcr/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
20
23
  openepd/api/pcr/sync_api.py,sha256=Riu77h8uLJngKpITOiXYmO7mzjAHpYskUJ6ynyfNG78,1557
21
- openepd/api/sync_client.py,sha256=kVirNhExF92vr2VXnzxNFVUJwnbgC_VR8vzV47twQKQ,2287
24
+ openepd/api/sync_client.py,sha256=IurnhZrkBQoQIbbfon6TPuhjGpAV_CSTJNeXjIiN0QI,3105
22
25
  openepd/api/test/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
23
26
  openepd/api/utils.py,sha256=FSY2W8zTXGTvJAJACMi4nibpo-9m1HXkTCH8kdAYlzQ,875
24
27
  openepd/bundle/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
@@ -33,13 +36,13 @@ openepd/model/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
33
36
  openepd/model/base.py,sha256=o6miTbb4d2BRQ6epN5Jn8mIMkAeoAucd_3op7aEMELc,9044
34
37
  openepd/model/category.py,sha256=IQXNGQFQmFZ_H9PRONloX_UOSf1sTMDq1rM1yz8JR0Y,1639
35
38
  openepd/model/common.py,sha256=aa_bfotPybPoYyzHtwj5E5X1T-fCEyznMfVUWvpUhiM,5460
36
- openepd/model/declaration.py,sha256=zV1Xpv3a5jsQ62oN4Kg3gXFqsDpGr-9CncVwHB3ZugA,8578
39
+ openepd/model/declaration.py,sha256=w-wC5G8QmO8JxnUyMKfrKARer3VIMbs_vQr3SP_BdCE,8638
37
40
  openepd/model/epd.py,sha256=RtUeDq1869JJe5fUu-aP31jl_HRAO21NXcLQvRYmQLs,9030
38
41
  openepd/model/factory.py,sha256=XP7eeQNW5tqwX_4hfuEb3lK6BFQDb4KB0fSN0r8-lCU,2656
39
- openepd/model/generic_estimate.py,sha256=xPZmzYzSrHLPSL_2evtAycQFOJAec_3fEPAKaxbppsM,4424
40
- openepd/model/geography.py,sha256=G3Oz3QBw5n-RiSCAv-vAGxrOZBhwIT5rASnPlo9dkcs,42095
41
- openepd/model/industry_epd.py,sha256=t6s9JrfHJVJo_egQt6RdyE9u3t8rZi32efM-MoaV8ag,3234
42
- openepd/model/lcia.py,sha256=sDZIxyggqHIISCUocgvIEgkmqPLGNSEA3-zUd7TEgsw,18430
42
+ openepd/model/generic_estimate.py,sha256=kBRtW6yAXgV3YkflXOI1jy8Tav5k5y8M3MPnuKPCcA4,3938
43
+ openepd/model/geography.py,sha256=eCt15zXKDtiteNwXQ675cFwBXQqSpiGpIqwDo4nkOek,42091
44
+ openepd/model/industry_epd.py,sha256=39D8WlLrEUwHLwhUcOQgjcLFQq5xz3fpwkpIfTaXRek,3234
45
+ openepd/model/lcia.py,sha256=bnDVsEo429Go_EneVOkXYIxDu2soxrgxyfzU4OhDR3Q,18827
43
46
  openepd/model/org.py,sha256=FHcYh2WOOQrCMyzm0Ow-iP79jMTBPcneidjH6NXIklA,3760
44
47
  openepd/model/pcr.py,sha256=SwqLWMj9k_jqIzxz5mh6ttqvtLCspKSpywF5YTBOMsA,5397
45
48
  openepd/model/specs/README.md,sha256=W5LSMpZuW5x36cKS4HRfeFsClsRf8J9yHMMICghdc0s,862
@@ -94,7 +97,7 @@ openepd/model/validation/quantity.py,sha256=kzug0MZ3Ao0zeVzN-aleyxUg5hA_7D5tNOOe
94
97
  openepd/model/versioning.py,sha256=R_zm6rCrgF3vlJQYbpyWhirdS_Oek16cv_mvZmpuE8I,4473
95
98
  openepd/patch_pydantic.py,sha256=xrkzblatmU9HBzukWkp1cPq9ZSuohoz1p0pQqVKSlKs,4122
96
99
  openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
- openepd-4.10.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
98
- openepd-4.10.0.dist-info/METADATA,sha256=JFHSPXma_sUGfRJJjmbq_UJF6Cn_G8D-AmaSRErL3N4,8535
99
- openepd-4.10.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
100
- openepd-4.10.0.dist-info/RECORD,,
100
+ openepd-4.11.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
101
+ openepd-4.11.0.dist-info/METADATA,sha256=r1eiXSYJwvSwLQAW_vxG2Q96PtzvTnTtC4mSEwZlPBA,8705
102
+ openepd-4.11.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
103
+ openepd-4.11.0.dist-info/RECORD,,