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.
- openepd/__init__.py +1 -1
- openepd/__version__.py +2 -2
- openepd/api/__init__.py +19 -0
- openepd/api/base_sync_client.py +550 -0
- openepd/api/category/__init__.py +19 -0
- openepd/api/category/dto.py +25 -0
- openepd/api/category/sync_api.py +44 -0
- openepd/api/common.py +239 -0
- openepd/api/dto/__init__.py +19 -0
- openepd/api/dto/base.py +41 -0
- openepd/api/dto/common.py +115 -0
- openepd/api/dto/meta.py +69 -0
- openepd/api/dto/mf.py +59 -0
- openepd/api/dto/params.py +19 -0
- openepd/api/epd/__init__.py +19 -0
- openepd/api/epd/dto.py +121 -0
- openepd/api/epd/sync_api.py +105 -0
- openepd/api/errors.py +86 -0
- openepd/api/pcr/__init__.py +19 -0
- openepd/api/pcr/dto.py +41 -0
- openepd/api/pcr/sync_api.py +49 -0
- openepd/api/sync_client.py +67 -0
- openepd/api/test/__init__.py +19 -0
- openepd/bundle/__init__.py +1 -1
- openepd/bundle/base.py +1 -1
- openepd/bundle/model.py +5 -6
- openepd/bundle/reader.py +5 -5
- openepd/bundle/writer.py +5 -4
- openepd/compat/__init__.py +19 -0
- openepd/compat/pydantic.py +29 -0
- openepd/model/__init__.py +1 -1
- openepd/model/base.py +114 -15
- openepd/model/category.py +39 -0
- openepd/model/common.py +33 -25
- openepd/model/epd.py +97 -78
- openepd/model/factory.py +48 -0
- openepd/model/lcia.py +24 -13
- openepd/model/org.py +28 -18
- openepd/model/pcr.py +42 -14
- openepd/model/specs/README.md +19 -0
- openepd/model/specs/__init__.py +20 -4
- openepd/model/specs/aluminium.py +67 -0
- openepd/model/specs/asphalt.py +87 -0
- openepd/model/specs/base.py +60 -0
- openepd/model/specs/concrete.py +453 -23
- openepd/model/specs/glass.py +404 -0
- openepd/model/specs/steel.py +193 -0
- openepd/model/specs/wood.py +130 -0
- openepd/model/standard.py +2 -3
- openepd/model/validation/__init__.py +19 -0
- openepd/model/validation/common.py +59 -0
- openepd/model/validation/numbers.py +26 -0
- openepd/model/validation/quantity.py +131 -0
- openepd/model/versioning.py +129 -0
- {openepd-2.0.0.dist-info → openepd-3.0.0.dist-info}/METADATA +36 -5
- openepd-3.0.0.dist-info/RECORD +59 -0
- openepd-2.0.0.dist-info/RECORD +0 -22
- {openepd-2.0.0.dist-info → openepd-3.0.0.dist-info}/LICENSE +0 -0
- {openepd-2.0.0.dist-info → openepd-3.0.0.dist-info}/WHEEL +0 -0
openepd/api/common.py
ADDED
@@ -0,0 +1,239 @@
|
|
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 collections.abc import Iterable
|
21
|
+
from contextlib import contextmanager
|
22
|
+
from datetime import datetime, timedelta
|
23
|
+
import threading
|
24
|
+
from time import sleep
|
25
|
+
from typing import Callable, Generic, Iterator, cast
|
26
|
+
|
27
|
+
from openepd.api.dto.common import DEFAULT_PAGE_SIZE, MetaCollectionDto, OpenEpdApiResponse
|
28
|
+
from openepd.api.dto.meta import PagingMeta, PagingMetaMixin
|
29
|
+
from openepd.model.base import TOpenEpdObject
|
30
|
+
|
31
|
+
|
32
|
+
class Throttler:
|
33
|
+
"""Throttle calls to a function to a certain rate."""
|
34
|
+
|
35
|
+
def __init__(self, rate_per_sec: float) -> None:
|
36
|
+
"""
|
37
|
+
Construct a throttler.
|
38
|
+
|
39
|
+
:param rate_per_sec: number of calls to throttle per second
|
40
|
+
"""
|
41
|
+
super().__init__()
|
42
|
+
|
43
|
+
self.rate: float = rate_per_sec
|
44
|
+
|
45
|
+
self.__count_lock = threading.Lock()
|
46
|
+
self.__time_lock = threading.Lock()
|
47
|
+
|
48
|
+
self.__count = 0
|
49
|
+
self.__start = datetime.now()
|
50
|
+
self.__time_limit = timedelta(seconds=1)
|
51
|
+
|
52
|
+
@contextmanager
|
53
|
+
def throttle(self):
|
54
|
+
"""Create context manager which throttles inside the context."""
|
55
|
+
with self.__count_lock:
|
56
|
+
count = self.__count
|
57
|
+
|
58
|
+
with self.__time_lock:
|
59
|
+
diff = datetime.now() - self.__start
|
60
|
+
if diff < self.__time_limit and count >= self.rate:
|
61
|
+
seconds = (self.__time_limit - diff).total_seconds()
|
62
|
+
sleep(seconds)
|
63
|
+
self.__start = datetime.now()
|
64
|
+
self.__count = count - self.rate
|
65
|
+
|
66
|
+
with self.__count_lock:
|
67
|
+
self.__count += 1
|
68
|
+
|
69
|
+
yield
|
70
|
+
|
71
|
+
|
72
|
+
class StreamingListResponse(Iterable[TOpenEpdObject], Generic[TOpenEpdObject]):
|
73
|
+
"""
|
74
|
+
Iterator over a list of objects which could be from remote API in batches by given fetch function.
|
75
|
+
|
76
|
+
This class could work only with OpenEpdApiResponse which:
|
77
|
+
a) contains a list of objects in payload
|
78
|
+
b) contains PagingMeta in meta
|
79
|
+
|
80
|
+
Typical use case:
|
81
|
+
|
82
|
+
stream: StreamingListResponse[Epd] # Assume we collected this from somewhere (e.g. from API Client)
|
83
|
+
|
84
|
+
# Iterate over all EPDs (this will fetch the next page when needed, one single page is buffered)
|
85
|
+
for epd in stream:
|
86
|
+
print(epd)
|
87
|
+
print("Current page: ", stream.current_page)
|
88
|
+
|
89
|
+
# Get specific page
|
90
|
+
page = stream.goto_page(4)
|
91
|
+
|
92
|
+
# Get paging information
|
93
|
+
stream.get_paging_meta()
|
94
|
+
# or
|
95
|
+
stream.get_get_total_pages(), stream.get_total_items()
|
96
|
+
|
97
|
+
# Iterate starting from specific page
|
98
|
+
for epd in stream.iterator(4):
|
99
|
+
print(epd)
|
100
|
+
# Alternative approach
|
101
|
+
stream.goto_page(4)
|
102
|
+
for epd in stream:
|
103
|
+
print(epd)
|
104
|
+
"""
|
105
|
+
|
106
|
+
def __init__(
|
107
|
+
self,
|
108
|
+
fetch_handler: Callable[[int, int], OpenEpdApiResponse[list[TOpenEpdObject], MetaCollectionDto]],
|
109
|
+
auto_init: bool = True,
|
110
|
+
page_size: int | None = None,
|
111
|
+
):
|
112
|
+
self.__fetch_handler = fetch_handler
|
113
|
+
self.__page_size = page_size or DEFAULT_PAGE_SIZE
|
114
|
+
self.__current_page = 0
|
115
|
+
self.__recent_response: OpenEpdApiResponse[list[TOpenEpdObject], MetaCollectionDto] | None = None
|
116
|
+
if auto_init:
|
117
|
+
self.goto_page(1)
|
118
|
+
|
119
|
+
def goto_page(self, page_num: int, force_reload: bool = False) -> list[TOpenEpdObject]:
|
120
|
+
"""
|
121
|
+
Go to the given page and return items as result.
|
122
|
+
|
123
|
+
This will query remote server to retrieve given page, the state of iterator will be updated accordingly.
|
124
|
+
All information from the internal buffer will be overridden.
|
125
|
+
|
126
|
+
:param page_num: page number to retrieve
|
127
|
+
:param force_reload: if True, force reload of the page even if it was already loaded
|
128
|
+
:return: list of items on the page
|
129
|
+
"""
|
130
|
+
if page_num <= 0:
|
131
|
+
raise ValueError("Page number must be positive")
|
132
|
+
if self.__current_page != page_num or force_reload:
|
133
|
+
self.__recent_response = self.__fetch_handler(page_num, self.__page_size)
|
134
|
+
self.__current_page = page_num
|
135
|
+
if self.__recent_response is None:
|
136
|
+
raise RuntimeError("Response is empty, this should not happen, check if fetch_handler is compatible")
|
137
|
+
if self.__recent_response.payload is None:
|
138
|
+
raise ValueError("Response does not contain payload")
|
139
|
+
if not isinstance(self.__recent_response.payload, list):
|
140
|
+
raise ValueError("Response does not contain a list")
|
141
|
+
if self.__recent_response.meta is None:
|
142
|
+
raise ValueError("Response does not contain meta")
|
143
|
+
if not isinstance(self.__recent_response.meta, PagingMetaMixin):
|
144
|
+
raise ValueError("Response does not contain paging meta")
|
145
|
+
return self.__recent_response.payload
|
146
|
+
|
147
|
+
def get_paging_meta(self) -> PagingMeta:
|
148
|
+
"""
|
149
|
+
Get paging meta from the most recent response.
|
150
|
+
|
151
|
+
If object is not initialized (no pages were retrieved yet), the first page will be fetched automatically.
|
152
|
+
See also: get_meta()
|
153
|
+
:return: paging meta
|
154
|
+
"""
|
155
|
+
paging_meta = cast(PagingMetaMixin, self.get_meta()).paging
|
156
|
+
if paging_meta is None:
|
157
|
+
raise ValueError("Response does not contain paging meta")
|
158
|
+
return paging_meta
|
159
|
+
|
160
|
+
def get_meta(self) -> MetaCollectionDto:
|
161
|
+
"""
|
162
|
+
Get meta from the most recent response.
|
163
|
+
|
164
|
+
If object is not initialized (no pages were retrieved yet), the first page will be fetched automatically.
|
165
|
+
:return: paging meta
|
166
|
+
"""
|
167
|
+
self._ensure_initialized()
|
168
|
+
return self.__recent_response.meta # type: ignore
|
169
|
+
|
170
|
+
@property
|
171
|
+
def current_page(self) -> int:
|
172
|
+
"""Get current page number (numbering is 1-based)."""
|
173
|
+
return self.__current_page
|
174
|
+
|
175
|
+
def get_total_pages(self) -> int:
|
176
|
+
"""Get total number of pages."""
|
177
|
+
return self.get_paging_meta().total_pages
|
178
|
+
|
179
|
+
def get_total_count(self) -> int:
|
180
|
+
"""Get total number of items."""
|
181
|
+
return self.get_paging_meta().total_count
|
182
|
+
|
183
|
+
def has_next_page(self) -> bool:
|
184
|
+
"""Check if there is a next page."""
|
185
|
+
return self.current_page < self.get_total_pages()
|
186
|
+
|
187
|
+
def reset(self):
|
188
|
+
"""Reset iterator to the very beginning, cleanup internal buffers."""
|
189
|
+
self.__current_page = 0
|
190
|
+
self.__recent_response = None
|
191
|
+
|
192
|
+
def __iter__(self) -> Iterator[TOpenEpdObject]:
|
193
|
+
"""
|
194
|
+
Iterate over all items, when needed the new pages from server will be requested.
|
195
|
+
|
196
|
+
Iteration from starts from the current page.
|
197
|
+
"""
|
198
|
+
return self.iterator(self.current_page)
|
199
|
+
|
200
|
+
def iterator(self, start_from_page: int = 1) -> Iterator[TOpenEpdObject]:
|
201
|
+
"""
|
202
|
+
Iterate over all items, when needed the new pages from server will be requested.
|
203
|
+
|
204
|
+
:param start_from_page: page number to start from (1-based)
|
205
|
+
"""
|
206
|
+
if start_from_page <= 0:
|
207
|
+
start_from_page = 1
|
208
|
+
self.goto_page(start_from_page)
|
209
|
+
while True:
|
210
|
+
items = self.goto_page(self.current_page)
|
211
|
+
for x in items:
|
212
|
+
yield x
|
213
|
+
if not self.has_next_page():
|
214
|
+
return # no more pages
|
215
|
+
else:
|
216
|
+
self.goto_page(self.current_page + 1)
|
217
|
+
|
218
|
+
def __len__(self):
|
219
|
+
return self.get_total_count()
|
220
|
+
|
221
|
+
def _is_initialized(self) -> bool:
|
222
|
+
"""Check if object is initialized (at least one page was retrieved)."""
|
223
|
+
return self.__recent_response is not None
|
224
|
+
|
225
|
+
def _ensure_initialized(self):
|
226
|
+
"""Ensure that object is initialized, if not - request the first page."""
|
227
|
+
if not self._is_initialized():
|
228
|
+
self.goto_page(1)
|
229
|
+
|
230
|
+
|
231
|
+
def no_trailing_slash(val: str) -> str:
|
232
|
+
"""
|
233
|
+
Remove all trailing slashes from the given string. Might be useful to normalize URLs.
|
234
|
+
|
235
|
+
Non-string input is considered as error.
|
236
|
+
"""
|
237
|
+
while val.endswith("/"):
|
238
|
+
val = val[:-1]
|
239
|
+
return val
|
@@ -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/dto/base.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
|
+
import abc
|
21
|
+
|
22
|
+
from openepd.compat.pydantic import pyd
|
23
|
+
|
24
|
+
|
25
|
+
class BaseOpenEpdApiModel(pyd.BaseModel):
|
26
|
+
"""Base class for OpenEPD API DTOs."""
|
27
|
+
|
28
|
+
class Config:
|
29
|
+
extra = pyd.Extra.ignore
|
30
|
+
|
31
|
+
|
32
|
+
class BaseMetaDto(BaseOpenEpdApiModel, metaclass=abc.ABCMeta):
|
33
|
+
"""Base class for all meta DTOs."""
|
34
|
+
|
35
|
+
pass
|
36
|
+
|
37
|
+
|
38
|
+
class MetaExtensionBase(BaseOpenEpdApiModel):
|
39
|
+
"""Base class for custom meta extensions."""
|
40
|
+
|
41
|
+
pass
|
@@ -0,0 +1,115 @@
|
|
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
|
+
import abc
|
21
|
+
import datetime
|
22
|
+
from typing import Final, Generic, TypeAlias, TypeVar
|
23
|
+
|
24
|
+
from openepd.api.dto.base import BaseMetaDto, BaseOpenEpdApiModel, MetaExtensionBase
|
25
|
+
from openepd.api.dto.meta import PerformanceMetaMixin
|
26
|
+
from openepd.compat.pydantic import pyd, pyd_generics
|
27
|
+
from openepd.model.base import AnySerializable, BaseOpenEpdSchema
|
28
|
+
|
29
|
+
DEFAULT_PAGE_SIZE: Final[int] = 100
|
30
|
+
MAX_PAGE_SIZE: Final[int] = 250
|
31
|
+
|
32
|
+
|
33
|
+
class AuditableDto(BaseOpenEpdApiModel, metaclass=abc.ABCMeta):
|
34
|
+
"""Base class for all DTOs that hold audit information."""
|
35
|
+
|
36
|
+
created_by: str = pyd.Field(
|
37
|
+
title="Created By",
|
38
|
+
example="johnsmith@cqd.io",
|
39
|
+
description="User's email or script name that created this list.",
|
40
|
+
)
|
41
|
+
updated_by: str = pyd.Field(
|
42
|
+
title="Updated By",
|
43
|
+
example="bobbuilder@buildingtransparency.org",
|
44
|
+
description="User's email or script name that updated this list last time.",
|
45
|
+
)
|
46
|
+
created_on: datetime.datetime = pyd.Field(
|
47
|
+
title="Created On",
|
48
|
+
example="2019-06-13T13:17:09+00:00",
|
49
|
+
description="A timestamp when this object has been created "
|
50
|
+
"in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.",
|
51
|
+
)
|
52
|
+
updated_on: datetime.datetime = pyd.Field(
|
53
|
+
title="Updated On",
|
54
|
+
example="2020-07-13T13:17:09+00:00",
|
55
|
+
description="A timestamp when this object has been updated last time "
|
56
|
+
"in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.",
|
57
|
+
)
|
58
|
+
|
59
|
+
|
60
|
+
Payload: TypeAlias = AnySerializable
|
61
|
+
TPayload = TypeVar("TPayload", bound=Payload)
|
62
|
+
TMetaDto = TypeVar("TMetaDto", bound=BaseMetaDto)
|
63
|
+
TMetaExtension = TypeVar("TMetaExtension", bound=MetaExtensionBase)
|
64
|
+
|
65
|
+
|
66
|
+
class MetaCollectionDto(BaseOpenEpdApiModel, pyd_generics.GenericModel, Generic[TMetaExtension]):
|
67
|
+
"""
|
68
|
+
This class is intended to be used as a container for different meta objects.
|
69
|
+
|
70
|
+
From a specific controller, you should return a specific subclass of MetaCollectionDto and appropriate mixins. This
|
71
|
+
would allow to retain type information to generate schema for meta section of response.
|
72
|
+
|
73
|
+
For example, EPD Search method, which should return some metadata about performance, material filter, and paging,
|
74
|
+
would return a concrete subclass of MetaCollectionDto like this one:
|
75
|
+
|
76
|
+
`class EpdSearchViewMeta(MaterialFilterMetaMixin, PagingMetaMixin, WarningMetaMixin, MetaCollectionDto)`
|
77
|
+
|
78
|
+
Mixins are used to define the resulting meta's dictionary-like structure, this would result in a json like:
|
79
|
+
```
|
80
|
+
{
|
81
|
+
"paging": {"page_size": 100, "total_count": 1, "total_pages": 1},
|
82
|
+
"ec3_warnings": null,
|
83
|
+
"material_filter": {...}
|
84
|
+
}
|
85
|
+
```
|
86
|
+
|
87
|
+
It is generified by the extension type of similar structure (key-dict value), which should not be a part of OpenEPD
|
88
|
+
spec. This allows to add custom meta objects to the response, which would be ignored by OpenEPD implementors.
|
89
|
+
"""
|
90
|
+
|
91
|
+
ext: TMetaExtension | None = None
|
92
|
+
|
93
|
+
class Config(BaseOpenEpdSchema.Config):
|
94
|
+
schema_extra = {
|
95
|
+
"description": "Base structure of the response meta section",
|
96
|
+
}
|
97
|
+
|
98
|
+
|
99
|
+
class BaseMeta(PerformanceMetaMixin, MetaCollectionDto[TMetaExtension], Generic[TMetaExtension], metaclass=abc.ABCMeta):
|
100
|
+
"""Base class for creating meta objects specific to a controller."""
|
101
|
+
|
102
|
+
pass
|
103
|
+
|
104
|
+
|
105
|
+
TMeta = TypeVar("TMeta", bound=MetaCollectionDto, covariant=True)
|
106
|
+
|
107
|
+
|
108
|
+
class OpenEpdApiResponse(pyd_generics.GenericModel, BaseOpenEpdApiModel, Generic[TPayload, TMeta]):
|
109
|
+
"""Standard DTO representing response from OpenEPD API server."""
|
110
|
+
|
111
|
+
payload: TPayload
|
112
|
+
# there is an issue with using covariant type variables as parameters when used for container mutable types,
|
113
|
+
# as described in https://github.com/python/mypy/issues/7049
|
114
|
+
# However, in our workflow TMeta is not a container type which is further returned back to caller.
|
115
|
+
meta: TMeta # type: ignore[misc]
|
openepd/api/dto/meta.py
ADDED
@@ -0,0 +1,69 @@
|
|
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 BaseMetaDto, BaseOpenEpdApiModel
|
21
|
+
from openepd.compat.pydantic import pyd
|
22
|
+
|
23
|
+
|
24
|
+
class PerformanceMeta(BaseMetaDto):
|
25
|
+
"""Meta for performance information."""
|
26
|
+
|
27
|
+
execution_time_ms: int
|
28
|
+
|
29
|
+
|
30
|
+
class PerformanceMetaMixin(BaseMetaDto):
|
31
|
+
"""Mixin for adding performance meta to MetaCollection."""
|
32
|
+
|
33
|
+
performance: PerformanceMeta | None = None
|
34
|
+
|
35
|
+
|
36
|
+
class PagingMeta(BaseMetaDto):
|
37
|
+
"""Meta for paging information."""
|
38
|
+
|
39
|
+
total_count: int = pyd.Field(
|
40
|
+
title="Total results", example=1233, description="Total number of records for the search"
|
41
|
+
)
|
42
|
+
total_pages: int = pyd.Field(title="Total pages", example=20, description="Total pages available")
|
43
|
+
page_size: int = pyd.Field(title="Page size", example=150, description="Number of records in page")
|
44
|
+
|
45
|
+
|
46
|
+
class PagingMetaMixin(BaseOpenEpdApiModel):
|
47
|
+
"""Mixin for adding paging meta to MetaCollection."""
|
48
|
+
|
49
|
+
paging: PagingMeta | None
|
50
|
+
|
51
|
+
|
52
|
+
class WarningMessageDto(BaseOpenEpdApiModel):
|
53
|
+
"""DTO for warning messages."""
|
54
|
+
|
55
|
+
message: str = pyd.Field(
|
56
|
+
title="Warning message", example="Categories limited during search, see effective_omf in meta"
|
57
|
+
)
|
58
|
+
code: str = pyd.Field(title="Warning code", example="CATEGORIES_LIMITED")
|
59
|
+
field: str | None = pyd.Field(
|
60
|
+
title="Field",
|
61
|
+
description="Field to which the warning relates",
|
62
|
+
example="subcategories",
|
63
|
+
)
|
64
|
+
|
65
|
+
|
66
|
+
class WarningMetaMixin(BaseOpenEpdApiModel):
|
67
|
+
"""Mixin for adding warnings meta to MetaCollection."""
|
68
|
+
|
69
|
+
warnings: list[WarningMessageDto] | None = None
|
openepd/api/dto/mf.py
ADDED
@@ -0,0 +1,59 @@
|
|
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 MaterialFilterDefinition(BaseOpenEpdApiModel):
|
25
|
+
"""
|
26
|
+
Material filter definition.
|
27
|
+
|
28
|
+
This object includes material filter itself as well as its hash.
|
29
|
+
"""
|
30
|
+
|
31
|
+
mf: str = pyd.Field(
|
32
|
+
title="MaterialFilter",
|
33
|
+
example='!EC3 search("AluminiumBillets") !pragma oMF("1.0/1")',
|
34
|
+
description="MaterialFilter in string format",
|
35
|
+
)
|
36
|
+
mf_hash: str = pyd.Field(
|
37
|
+
title="MaterialFilter hash",
|
38
|
+
example="22bf5b78cee5b79e1c76e818873d521c3972688b",
|
39
|
+
description="MaterialFilter hash. Can be used to compare filters for equality, put to cache etc.",
|
40
|
+
)
|
41
|
+
|
42
|
+
|
43
|
+
class MaterialFilterMeta(BaseOpenEpdApiModel):
|
44
|
+
"""Meta holding supplementary information about OMF query execution."""
|
45
|
+
|
46
|
+
excluded_fields: list[str] | None = pyd.Field(
|
47
|
+
example=["building_jurisdiction", "jurisdiction"],
|
48
|
+
description="list of fields excluded by server process for any reason",
|
49
|
+
default=None,
|
50
|
+
)
|
51
|
+
effective_omf: MaterialFilterDefinition = pyd.Field(
|
52
|
+
description="Effective OpenMaterialFilter as applied to search, after transformations if any"
|
53
|
+
)
|
54
|
+
|
55
|
+
|
56
|
+
class MaterialFilterMetaMixin(BaseOpenEpdApiModel):
|
57
|
+
"""Mixing for adding MaterialFilterMeta to MetaCollection."""
|
58
|
+
|
59
|
+
material_filter: MaterialFilterMeta | None
|
@@ -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
|
+
#
|
@@ -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
|
+
#
|