openepd 2.0.0__py3-none-any.whl → 3.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.
Files changed (59) hide show
  1. openepd/__init__.py +1 -1
  2. openepd/__version__.py +2 -2
  3. openepd/api/__init__.py +19 -0
  4. openepd/api/base_sync_client.py +550 -0
  5. openepd/api/category/__init__.py +19 -0
  6. openepd/api/category/dto.py +25 -0
  7. openepd/api/category/sync_api.py +44 -0
  8. openepd/api/common.py +239 -0
  9. openepd/api/dto/__init__.py +19 -0
  10. openepd/api/dto/base.py +41 -0
  11. openepd/api/dto/common.py +115 -0
  12. openepd/api/dto/meta.py +69 -0
  13. openepd/api/dto/mf.py +59 -0
  14. openepd/api/dto/params.py +19 -0
  15. openepd/api/epd/__init__.py +19 -0
  16. openepd/api/epd/dto.py +121 -0
  17. openepd/api/epd/sync_api.py +105 -0
  18. openepd/api/errors.py +86 -0
  19. openepd/api/pcr/__init__.py +19 -0
  20. openepd/api/pcr/dto.py +41 -0
  21. openepd/api/pcr/sync_api.py +49 -0
  22. openepd/api/sync_client.py +67 -0
  23. openepd/api/test/__init__.py +19 -0
  24. openepd/bundle/__init__.py +1 -1
  25. openepd/bundle/base.py +1 -1
  26. openepd/bundle/model.py +5 -6
  27. openepd/bundle/reader.py +5 -5
  28. openepd/bundle/writer.py +5 -4
  29. openepd/compat/__init__.py +19 -0
  30. openepd/compat/pydantic.py +29 -0
  31. openepd/model/__init__.py +1 -1
  32. openepd/model/base.py +114 -15
  33. openepd/model/category.py +39 -0
  34. openepd/model/common.py +33 -25
  35. openepd/model/epd.py +97 -78
  36. openepd/model/factory.py +48 -0
  37. openepd/model/lcia.py +24 -13
  38. openepd/model/org.py +28 -18
  39. openepd/model/pcr.py +42 -14
  40. openepd/model/specs/README.md +19 -0
  41. openepd/model/specs/__init__.py +20 -4
  42. openepd/model/specs/aluminium.py +67 -0
  43. openepd/model/specs/asphalt.py +87 -0
  44. openepd/model/specs/base.py +60 -0
  45. openepd/model/specs/concrete.py +453 -23
  46. openepd/model/specs/glass.py +404 -0
  47. openepd/model/specs/steel.py +193 -0
  48. openepd/model/specs/wood.py +130 -0
  49. openepd/model/standard.py +2 -3
  50. openepd/model/validation/__init__.py +19 -0
  51. openepd/model/validation/common.py +59 -0
  52. openepd/model/validation/numbers.py +26 -0
  53. openepd/model/validation/quantity.py +131 -0
  54. openepd/model/versioning.py +129 -0
  55. {openepd-2.0.0.dist-info → openepd-3.0.0.dist-info}/METADATA +36 -5
  56. openepd-3.0.0.dist-info/RECORD +59 -0
  57. openepd-2.0.0.dist-info/RECORD +0 -22
  58. {openepd-2.0.0.dist-info → openepd-3.0.0.dist-info}/LICENSE +0 -0
  59. {openepd-2.0.0.dist-info → openepd-3.0.0.dist-info}/WHEEL +0 -0
openepd/api/epd/dto.py ADDED
@@ -0,0 +1,121 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
20
+ from typing import TypeAlias
21
+
22
+ from openepd.api.dto.base import BaseOpenEpdApiModel
23
+ from openepd.api.dto.common import BaseMeta, OpenEpdApiResponse
24
+ from openepd.api.dto.meta import PagingMetaMixin, WarningMetaMixin
25
+ from openepd.api.dto.mf import MaterialFilterMetaMixin
26
+ from openepd.compat.pydantic import pyd
27
+ from openepd.model.common import Amount
28
+ from openepd.model.epd import Epd
29
+
30
+
31
+ class StatisticsDto(BaseOpenEpdApiModel):
32
+ """
33
+ DTO describes statistics of EPD.
34
+
35
+ Statistics contains aggregated parameters such as percentiles distributions of GWP and other parameters.
36
+ """
37
+
38
+ # percentiles
39
+ pct10_gwp: float = pyd.Field(
40
+ description="10th percentile GWP for this statistics measured in kgCO2e per declared unit"
41
+ )
42
+ achievable_target: float = pyd.Field(
43
+ description="Achievable target. 20th percentile of GWP measured in kgCO2e per declared unit", example=445.65
44
+ )
45
+ pct30_gwp: float = pyd.Field(
46
+ description="30th percentile GWP for this statistics measured in kgCO2e per declared unit"
47
+ )
48
+ pct40_gwp: float = pyd.Field(
49
+ description="40th percentile GWP for this statistics measured in kgCO2e per declared unit"
50
+ )
51
+ pct50_gwp: float = pyd.Field(
52
+ description="50th percentile GWP for this statistics measured in kgCO2e per declared unit"
53
+ )
54
+ pct60_gwp: float = pyd.Field(
55
+ description="60th percentile GWP for this statistics measured in kgCO2e per declared unit"
56
+ )
57
+ pct70_gwp: float = pyd.Field(
58
+ description="70th percentile GWP for this statistics measured in kgCO2e per declared unit"
59
+ )
60
+ conservative_estimate: float = pyd.Field(
61
+ description="Conservative estimate. 80th percentile of GWP per declared unit measured in kgCO2e",
62
+ example=640.778,
63
+ )
64
+ pct90_gwp: float = pyd.Field(
65
+ description="70th percentile GWP for this statistics measured in kgCO2e per declared unit"
66
+ )
67
+
68
+ # stats
69
+ average: float = pyd.Field(description="Average GWP in kgCO2e per declared unit", example=554.2)
70
+ min: float | None = pyd.Field(
71
+ description="Min GWP of returned results measured in kgCO2e per declared unit", example=998.3
72
+ )
73
+ max: float | None = pyd.Field(
74
+ description="Max GWP of returned results measured in kgCO2e per declared unit", example=120.0
75
+ )
76
+
77
+ # percentiles w/out burden of doubt
78
+ pct20_gwp_no_bod: float | None = pyd.Field(
79
+ description="20th percentile of GWP (kgCO2e per declared unit), no burden of doubt", example=120
80
+ )
81
+ pct40_gwp_no_bod: float | None = pyd.Field(
82
+ description="40th percentile of GWP (kgCO2e per declared unit), no burden of doubt", example=120
83
+ )
84
+ pct60_gwp_no_bod: float | None = pyd.Field(
85
+ description="60th percentile of GWP (kgCO2e per declared unit), no burden of doubt", example=120
86
+ )
87
+ pct80_gwp_no_bod: float | None = pyd.Field(
88
+ description="80th percentile of GWP (kgCO2e per declared unit), no burden of doubt", example=120
89
+ )
90
+ average_gwp_no_bod: float | None = pyd.Field(description="Average GWP, no burden of doubt", example=120)
91
+
92
+ # set parameters
93
+ standard_deviation: float = pyd.Field(description="Standard deviation", example=87.62)
94
+ epds_count: int = pyd.Field(description="Number of EPDs participated in statistics", example=55)
95
+ industry_epds_count: int = pyd.Field(
96
+ description="Number of Industry-wide EPDs participated in statistics", example=4
97
+ )
98
+ generic_estimates_count: int = pyd.Field(
99
+ description="Number of Generic Estimates participated in statistics", example=0
100
+ )
101
+
102
+ declared_unit: Amount = pyd.Field(
103
+ description="Declared unit for the statistics. "
104
+ "Statistical values - percentiles, averages etc - are based on this unit of product"
105
+ )
106
+
107
+
108
+ class EpdSearchMeta(MaterialFilterMetaMixin, PagingMetaMixin, WarningMetaMixin, BaseMeta):
109
+ """Metadata for EPD Search endpoint."""
110
+
111
+ pass
112
+
113
+
114
+ class EpdStatisticsMeta(MaterialFilterMetaMixin, WarningMetaMixin, BaseMeta):
115
+ """Metadata for EPD Statistics endpoint."""
116
+
117
+ pass
118
+
119
+
120
+ EpdSearchResponse: TypeAlias = OpenEpdApiResponse[list[Epd], EpdSearchMeta]
121
+ EpdStatisticsResponse: TypeAlias = OpenEpdApiResponse[StatisticsDto, EpdStatisticsMeta]
@@ -0,0 +1,105 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
20
+ from openepd.api.base_sync_client import BaseApiMethodGroup
21
+ from openepd.api.common import StreamingListResponse
22
+ from openepd.api.epd.dto import EpdSearchResponse, EpdStatisticsResponse, StatisticsDto
23
+ from openepd.model.epd import Epd
24
+
25
+
26
+ class EpdApi(BaseApiMethodGroup):
27
+ """API methods for EPDs."""
28
+
29
+ def get_by_openxpd_uuid(self, uuid: str) -> Epd:
30
+ """
31
+ Get EPD by OpenEPD UUID.
32
+
33
+ :param uuid: OpenEPD UUID
34
+ :return: EPD
35
+ :raise ObjectNotFound: if EPD is not found
36
+ """
37
+ content = self._client.do_request("get", f"/epds/{uuid}").json()
38
+ return Epd.parse_obj(content)
39
+
40
+ def find_raw(self, omf: str, page_num: int = 1, page_size: int = 10) -> EpdSearchResponse:
41
+ """
42
+ Find EPDs by Open Material Filter(OMF).
43
+
44
+ OMF is a query language for searching materials/EPDs, running statistics and so on.
45
+ It can exist in a string form, which is accepted by most of the endpoints.
46
+
47
+ :param omf: OMF - open material filter string (see OMF spec).
48
+ :param page_num: page number
49
+ :param page_size: page size
50
+ :return: the list of EPDs
51
+ """
52
+ content = self._client.do_request(
53
+ "get",
54
+ "/v2/epds/search",
55
+ params=dict(
56
+ omf=omf,
57
+ page_number=page_num,
58
+ page_size=page_size,
59
+ ),
60
+ ).json()
61
+ return EpdSearchResponse.parse_obj(content)
62
+
63
+ def find(self, omf: str, page_size: int | None = None) -> StreamingListResponse[Epd]:
64
+ """
65
+ Find EPDs by Open Material Filter(OMF).
66
+
67
+ OMF is a query language for searching materials/EPDs, running statistics and so on.
68
+ It can exist in a string form, which is accepted by most of the endpoints.
69
+
70
+ :param omf: OMF - open material filter string (see OMF spec).
71
+ :param page_size: page size, None for default
72
+ :return: streaming list of EPDs
73
+ """
74
+
75
+ def _get_page(p_num: int, p_size: int) -> EpdSearchResponse:
76
+ return self.find_raw(omf, page_num=p_num, page_size=p_size)
77
+
78
+ return StreamingListResponse[Epd](_get_page, page_size=page_size)
79
+
80
+ def get_statistics_raw(self, omf: str) -> EpdStatisticsResponse:
81
+ """
82
+ Get statistics for a given search query.
83
+
84
+ Statistics contains aggregated parameters such as percentiles distributions of GWP and other parameters.
85
+ Please note - in addition to product EPDs statistics might include industry-wide EPDs and even generic
86
+ estimates to provide a more complete picture where there is not enough product EPDs.
87
+
88
+ :param omf: OMF - open material filter string (see OMF spec).
89
+ :return: statistics wrapped in OpenEpdApiResponse
90
+ """
91
+ content = self._client.do_request("get", "/v2/epds/statistics", params=dict(omf=omf)).json()
92
+ return EpdStatisticsResponse.parse_obj(content)
93
+
94
+ def get_statistics(self, omf: str) -> StatisticsDto:
95
+ """
96
+ Get statistics for a given search query.
97
+
98
+ Statistics contains aggregated parameters such as percentiles distributions of GWP and other parameters.
99
+ Please note - in addition to product EPDs statistics might include industry-wide EPDs and even generic
100
+ estimates to provide a more complete picture where there is not enough product EPDs.
101
+
102
+ :param omf: OMF - open material filter string (see OMF spec).
103
+ :return: statistics wrapped in OpenEpdApiResponse
104
+ """
105
+ return self.get_statistics_raw(omf).payload
openepd/api/errors.py ADDED
@@ -0,0 +1,86 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
20
+ from typing import Any
21
+
22
+
23
+ class ApiError(Exception):
24
+ """Base class for all API errors."""
25
+
26
+ def __init__(
27
+ self, http_status: int, error_summary: str, response: Any = None, error_code: str | None = None
28
+ ) -> None:
29
+ super().__init__(error_summary)
30
+ self.error_summary = error_summary
31
+ self.http_status = http_status
32
+ self.error_code = error_code
33
+ self.response = response
34
+
35
+
36
+ class ObjectNotFound(ApiError):
37
+ """Object not found error."""
38
+
39
+ pass
40
+
41
+
42
+ class ServerError(ApiError):
43
+ """Server error."""
44
+
45
+ pass
46
+
47
+
48
+ class ValidationError(ApiError):
49
+ """Validation error."""
50
+
51
+ def __init__(
52
+ self,
53
+ http_status: int,
54
+ error_summary: str,
55
+ validation_errors: dict[str, list[str]] | None,
56
+ response: Any,
57
+ error_code: str | None,
58
+ ) -> None:
59
+ super().__init__(http_status, error_summary, response, error_code)
60
+ self.validation_errors: dict[str, list[str]] = validation_errors or {}
61
+
62
+ def __str__(self) -> str:
63
+ result: list[str] = ["Validation errors:"]
64
+ for code, errors in self.validation_errors.items():
65
+ result.append(f"{code}:")
66
+ for e in errors:
67
+ result.append(f" {e}")
68
+ return "\n".join(result)
69
+
70
+
71
+ class AuthError(ApiError):
72
+ """Common class for any authentication related errors."""
73
+
74
+ pass
75
+
76
+
77
+ class NotAuthorizedError(AuthError):
78
+ """Not authorized error."""
79
+
80
+ pass
81
+
82
+
83
+ class AccessDeniedError(AuthError):
84
+ """Access denied error."""
85
+
86
+ pass
@@ -0,0 +1,19 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
openepd/api/pcr/dto.py ADDED
@@ -0,0 +1,41 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
20
+ from openepd.api.dto.base import BaseOpenEpdApiModel
21
+ from openepd.compat.pydantic import pyd
22
+
23
+
24
+ class PcrRef(BaseOpenEpdApiModel):
25
+ """Reference to a PCR."""
26
+
27
+ id: str | None = pyd.Field(
28
+ description="The unique ID for this PCR. To ensure global uniqueness, should be registered "
29
+ "at open-xpd-uuid.cqd.io/register or a coordinating registry.",
30
+ example="ec3xpgq2",
31
+ default=None,
32
+ )
33
+ name: str | None = pyd.Field(
34
+ max_length=200,
35
+ description="Full document name as listed in source document",
36
+ example="c-PCR-003 Concrete and concrete elements (EN 16757)",
37
+ )
38
+ ref: pyd.AnyUrl | None = pyd.Field(
39
+ description="Reference to this PCR's JSON object",
40
+ example="https://openepd.buildingtransparency.org/api/pcrs/1u7zsed8",
41
+ )
@@ -0,0 +1,49 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
20
+ from openepd.api.base_sync_client import BaseApiMethodGroup
21
+ from openepd.api.pcr.dto import PcrRef
22
+ from openepd.model.pcr import Pcr
23
+
24
+
25
+ class PcrApi(BaseApiMethodGroup):
26
+ """API methods for EPDs."""
27
+
28
+ def get_by_openxpd_uuid(self, uuid: str) -> Pcr:
29
+ """
30
+ Get PCR by Open xPD UUID.
31
+
32
+ :param uuid: Open xPD UUID
33
+ :return: PCR
34
+ :raise ObjectNotFound: if PCR not found
35
+ :raise ValidationError: if openxpd_uuid is invalid
36
+ """
37
+ content = self._client.do_request("get", f"/pcrs/{uuid}").json()
38
+ return Pcr.parse_obj(content)
39
+
40
+ def create(self, pcr: Pcr) -> PcrRef:
41
+ """
42
+ Create a new PCR.
43
+
44
+ :param pcr: PCR to create
45
+ :return: reference to the created PCR
46
+ :raise ValidationError: if given object PCR is invalid
47
+ """
48
+ pcr_ref_obj = self._client.do_request("post", "/pcrs", json=pcr.to_serializable()).json()
49
+ return PcrRef.parse_obj(pcr_ref_obj)
@@ -0,0 +1,67 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
20
+ __all__ = ("OpenEpdApiClientSync",)
21
+
22
+ from requests.auth import AuthBase
23
+
24
+ from openepd.api.base_sync_client import SyncHttpClient, TokenAuth
25
+ from openepd.api.category.sync_api import CategoryApi
26
+ from openepd.api.epd.sync_api import EpdApi
27
+ from openepd.api.pcr.sync_api import PcrApi
28
+
29
+
30
+ class OpenEpdApiClientSync:
31
+ """Synchronous API client for OpenEPD."""
32
+
33
+ def __init__(self, base_url: str, auth_token: str | None, **kwargs) -> None:
34
+ """
35
+ Construct an API client.
36
+
37
+ :param base_url: base URL of the API
38
+ :param auth_token: authentication token
39
+ :param kwargs: additional arguments to pass to the HTTP client. See SyncHttpClient constructor for details.
40
+ """
41
+ super().__init__()
42
+ auth: AuthBase | None = TokenAuth(auth_token) if auth_token is not None else None
43
+ self._http_client = SyncHttpClient(base_url, auth=auth, **kwargs)
44
+ self.__epd_api: EpdApi | None = None
45
+ self.__pcr_api: PcrApi | None = None
46
+ self.__category_api: CategoryApi | None = None
47
+
48
+ @property
49
+ def epds(self) -> EpdApi:
50
+ """Get the EPD API."""
51
+ if self.__epd_api is None:
52
+ self.__epd_api = EpdApi(self._http_client)
53
+ return self.__epd_api
54
+
55
+ @property
56
+ def pcrs(self) -> PcrApi:
57
+ """Get the PCR API."""
58
+ if self.__pcr_api is None:
59
+ self.__pcr_api = PcrApi(self._http_client)
60
+ return self.__pcr_api
61
+
62
+ @property
63
+ def categories(self) -> CategoryApi:
64
+ """Get the Category API."""
65
+ if self.__category_api is None:
66
+ self.__category_api = CategoryApi(self._http_client)
67
+ return self.__category_api
@@ -0,0 +1,19 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2023 by C Change Labs Inc. www.c-change-labs.com
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
openepd/bundle/base.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2023 by C Change Labs Inc. www.c-change-labs.com
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
openepd/bundle/model.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2023 by C Change Labs Inc. www.c-change-labs.com
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -19,8 +19,7 @@
19
19
  #
20
20
  from enum import StrEnum
21
21
 
22
- import pydantic as pyd
23
-
22
+ from openepd.compat.pydantic import pyd
24
23
  from openepd.model.base import BaseOpenEpdSchema
25
24
 
26
25
 
@@ -77,10 +76,10 @@ class AssetInfo(BaseOpenEpdSchema):
77
76
  """The name of the asset."""
78
77
  type: AssetType
79
78
  """The type of the asset."""
80
- lang: str | None = None
79
+ lang: str | None
81
80
  """The language of the asset."""
82
- rel_type: str | None = None
83
- rel_asset: str | None = None
81
+ rel_type: str | None
82
+ rel_asset: str | None
84
83
  comment: str | None = pyd.Field(default=None)
85
84
  content_type: str | None = pyd.Field(default=None)
86
85
  size: int | None = pyd.Field(default=None)
openepd/bundle/reader.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2023 by C Change Labs Inc. www.c-change-labs.com
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ class DefaultBundleReader(BaseBundleReader):
35
35
  self._bundle_archive = zipfile.ZipFile(bundle_file, mode="r")
36
36
  try:
37
37
  with self._bundle_archive.open("manifest", "r") as manifest_stream:
38
- self.__manifest = BundleManifest.model_validate_json(manifest_stream.read())
38
+ self.__manifest = BundleManifest.parse_raw(manifest_stream.read())
39
39
  except Exception as e:
40
40
  raise ValueError("The bundle file is not valid. Manifest reading error: " + str(e)) from e
41
41
  try:
@@ -49,7 +49,7 @@ class DefaultBundleReader(BaseBundleReader):
49
49
 
50
50
  def get_manifest(self) -> BundleManifest:
51
51
  """Get the manifest of the bundle. Manifest object is immutable."""
52
- return self.__manifest.model_copy(deep=True)
52
+ return self.__manifest.copy(deep=True)
53
53
 
54
54
  def __create_asset_filter(
55
55
  self,
@@ -86,7 +86,7 @@ class DefaultBundleReader(BaseBundleReader):
86
86
  with self._bundle_archive.open("toc", "r") as toc_stream:
87
87
  toc_reader = csv.DictReader(io.TextIOWrapper(toc_stream, encoding="utf-8"), dialect="toc")
88
88
  for x in toc_reader:
89
- yield AssetInfo.model_validate(self.__preprocess_csv_dict(x))
89
+ yield AssetInfo.parse_obj(self.__preprocess_csv_dict(x))
90
90
 
91
91
  def __check_toc(self):
92
92
  with self._bundle_archive.open("toc", "r") as toc_stream:
@@ -158,4 +158,4 @@ class DefaultBundleReader(BaseBundleReader):
158
158
  if asset.type != obj_class.get_asset_type():
159
159
  raise ValueError(f"Asset type mismatch. Expected {obj_class.get_asset_type()}, got {asset.type}")
160
160
  with self._bundle_archive.open(asset.ref, "r") as asset_stream:
161
- return obj_class.model_validate_json(asset_stream.read())
161
+ return obj_class.parse_raw(asset_stream.read())
openepd/bundle/writer.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2023 by C Change Labs Inc. www.c-change-labs.com
2
+ # Copyright 2024 by C Change Labs Inc. www.c-change-labs.com
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -117,7 +117,8 @@ class DefaultBundleWriter(BaseBundleWriter):
117
117
  custom_data=custom_data,
118
118
  )
119
119
  self.__write_data_stream(
120
- asset_info, BytesIO(obj.model_dump_json(indent=2, exclude_unset=True, exclude_none=True).encode("utf-8"))
120
+ asset_info,
121
+ BytesIO(obj.json(indent=2, exclude_unset=True, exclude_none=True, by_alias=True).encode("utf-8")),
121
122
  )
122
123
  self.__register_entry(asset_info)
123
124
  return asset_info
@@ -125,7 +126,7 @@ class DefaultBundleWriter(BaseBundleWriter):
125
126
  def commit(self):
126
127
  """Write the manifest and TOC to the bundle. This will be called automatically when the bundle is closed."""
127
128
  with self._bundle_archive.open("manifest", "w") as manifest_stream:
128
- manifest_stream.write(self.__manifest.model_dump_json(indent=2, exclude_none=True).encode("utf-8"))
129
+ manifest_stream.write(self.__manifest.json(indent=2, exclude_none=True).encode("utf-8"))
129
130
  with self._bundle_archive.open("toc", "w") as toc_stream:
130
131
  toc_stream.write(self.__toc_buffer.getvalue().encode("utf-8"))
131
132
 
@@ -137,7 +138,7 @@ class DefaultBundleWriter(BaseBundleWriter):
137
138
  def __register_entry(self, asset_info: AssetInfo):
138
139
  if asset_info.ref in self.__added_entries:
139
140
  raise ValueError(f"Asset {asset_info.ref} already exists in the bundle.")
140
- self._toc_writer.writerow(asset_info.model_dump(mode="json", exclude_unset=True, exclude_none=True))
141
+ self._toc_writer.writerow(asset_info.dict(exclude_unset=True, exclude_none=True))
141
142
  self.__added_entries.add(asset_info.ref)
142
143
  type_counter = self.__manifest.assets.count_by_type.get(asset_info.type, 0) + 1
143
144
  self.__manifest.assets.count_by_type[asset_info.type] = type_counter
@@ -0,0 +1,19 @@
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
+ # This software was developed with support from the Skanska USA,
17
+ # Charles Pankow Foundation, Microsoft Sustainability Fund, Interface, MKA Foundation, and others.
18
+ # Find out more at www.BuildingTransparency.org
19
+ #