openepd 7.13.4__py3-none-any.whl → 7.14.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 +1 -1
- openepd/model/common.py +29 -2
- openepd/model/declaration.py +2 -18
- openepd/model/epd.py +12 -1
- openepd/model/org.py +13 -18
- {openepd-7.13.4.dist-info → openepd-7.14.0.dist-info}/METADATA +1 -1
- {openepd-7.13.4.dist-info → openepd-7.14.0.dist-info}/RECORD +9 -9
- {openepd-7.13.4.dist-info → openepd-7.14.0.dist-info}/LICENSE +0 -0
- {openepd-7.13.4.dist-info → openepd-7.14.0.dist-info}/WHEEL +0 -0
openepd/__version__.py
CHANGED
openepd/model/common.py
CHANGED
|
@@ -14,14 +14,16 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
from enum import StrEnum
|
|
17
|
-
|
|
17
|
+
import math
|
|
18
|
+
import re
|
|
19
|
+
from typing import Annotated, Any, Final, Self
|
|
18
20
|
|
|
19
21
|
import pydantic
|
|
20
22
|
import pydantic_core
|
|
21
23
|
|
|
22
24
|
from openepd.model.base import BaseOpenEpdSchema
|
|
23
25
|
|
|
24
|
-
DATA_URL_REGEX = r"^data:([-\w]+\/[-+\w.]+)?(;?\w+=[-\w]+)*(;base64)
|
|
26
|
+
DATA_URL_REGEX = r"^data:([-\w]+\/[-+\w.]+)?(;?\w+=[-\w]+)*(;base64)?,(.*)$"
|
|
25
27
|
"""
|
|
26
28
|
Regular expression pattern for matching Data URLs.
|
|
27
29
|
|
|
@@ -30,6 +32,14 @@ in web pages as if they were external resources.
|
|
|
30
32
|
The pattern matches the following format: data:[<media-type>][;base64],<data>
|
|
31
33
|
"""
|
|
32
34
|
|
|
35
|
+
DATA_URL_IMAGE_MAX_LENGTH: Final[int] = math.ceil(32 * 1024 * 4 / 3)
|
|
36
|
+
"""
|
|
37
|
+
Maximum allowed length of a data URL image string to ensure the decoded image is less than 32KB.
|
|
38
|
+
|
|
39
|
+
Base64 encoding overhead (approximately 33%) requires
|
|
40
|
+
limiting the encoded string length to 4/3 of the file size limit.
|
|
41
|
+
"""
|
|
42
|
+
|
|
33
43
|
|
|
34
44
|
class Amount(BaseOpenEpdSchema):
|
|
35
45
|
"""A value-and-unit pairing for amounts that do not have an uncertainty."""
|
|
@@ -372,3 +382,20 @@ class EnumGroupingAware:
|
|
|
372
382
|
def get_groupings(cls) -> list[list]:
|
|
373
383
|
"""Return logical groupings of the values."""
|
|
374
384
|
return []
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def validate_data_url(v: pydantic.AnyUrl | None, max_length: int) -> None:
|
|
388
|
+
"""
|
|
389
|
+
Validate data URL.
|
|
390
|
+
|
|
391
|
+
:param v: data URL string.
|
|
392
|
+
:param max_length: maximum allowed length.
|
|
393
|
+
:raises ValueError: if the data URL exceeds the maximum length or has invalid format.
|
|
394
|
+
:return: None
|
|
395
|
+
"""
|
|
396
|
+
if v and len(v) > max_length:
|
|
397
|
+
msg = f"URL must not exceed {max_length} characters"
|
|
398
|
+
raise ValueError(msg)
|
|
399
|
+
if v and v.scheme == "data" and not re.compile(DATA_URL_REGEX).match(str(v)):
|
|
400
|
+
msg = "Invalid data URL format"
|
|
401
|
+
raise ValueError(msg)
|
openepd/model/declaration.py
CHANGED
|
@@ -16,14 +16,11 @@
|
|
|
16
16
|
import abc
|
|
17
17
|
import datetime
|
|
18
18
|
from enum import StrEnum
|
|
19
|
-
import math
|
|
20
|
-
import re
|
|
21
|
-
from typing import Final
|
|
22
19
|
|
|
23
20
|
import pydantic
|
|
24
21
|
|
|
25
22
|
from openepd.model.base import BaseOpenEpdSchema, OpenXpdUUID, RootDocument
|
|
26
|
-
from openepd.model.common import
|
|
23
|
+
from openepd.model.common import DATA_URL_IMAGE_MAX_LENGTH, Amount, validate_data_url
|
|
27
24
|
from openepd.model.geography import Geography
|
|
28
25
|
from openepd.model.org import Org
|
|
29
26
|
from openepd.model.pcr import Pcr
|
|
@@ -36,14 +33,6 @@ DEVELOPER_DESCRIPTION = "The organization responsible for the underlying LCA (an
|
|
|
36
33
|
PROGRAM_OPERATOR_DESCRIPTION = "JSON object for program operator Org"
|
|
37
34
|
THIRD_PARTY_VERIFIER_DESCRIPTION = "JSON object for Org that performed a critical review of the EPD data"
|
|
38
35
|
|
|
39
|
-
PRODUCT_IMAGE_MAX_LENGTH: Final[int] = math.ceil(32 * 1024 * 4 / 3)
|
|
40
|
-
"""
|
|
41
|
-
Maximum length for product_image, product_image_small fields.
|
|
42
|
-
|
|
43
|
-
Image file size must be less than 32KB. Base64 encoding overhead (approximately 33%) requires
|
|
44
|
-
limiting the encoded string length to 4/3 of the file size limit.
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
36
|
|
|
48
37
|
class BaseDeclaration(RootDocument, abc.ABC):
|
|
49
38
|
"""Base class for declaration-related documents (EPDs, Industry-wide EPDs, Generic Estimates)."""
|
|
@@ -194,12 +183,7 @@ class BaseDeclaration(RootDocument, abc.ABC):
|
|
|
194
183
|
|
|
195
184
|
@pydantic.field_validator("product_image", "product_image_small")
|
|
196
185
|
def validate_product_image(cls, v: pydantic.AnyUrl | None) -> pydantic.AnyUrl | None:
|
|
197
|
-
|
|
198
|
-
msg = f"URL must not exceed {PRODUCT_IMAGE_MAX_LENGTH} characters"
|
|
199
|
-
raise ValueError(msg)
|
|
200
|
-
if v and v.scheme == "data" and not re.compile(DATA_URL_REGEX).match(str(v)):
|
|
201
|
-
msg = "Invalid data URL format"
|
|
202
|
-
raise ValueError(msg)
|
|
186
|
+
validate_data_url(v, DATA_URL_IMAGE_MAX_LENGTH)
|
|
203
187
|
return v
|
|
204
188
|
|
|
205
189
|
|
openepd/model/epd.py
CHANGED
|
@@ -16,7 +16,13 @@
|
|
|
16
16
|
import pydantic
|
|
17
17
|
|
|
18
18
|
from openepd.model.base import BaseDocumentFactory, OpenEpdDoctypes, OpenEpdExtension
|
|
19
|
-
from openepd.model.common import
|
|
19
|
+
from openepd.model.common import (
|
|
20
|
+
DATA_URL_IMAGE_MAX_LENGTH,
|
|
21
|
+
Ingredient,
|
|
22
|
+
WithAltIdsMixin,
|
|
23
|
+
WithAttachmentsMixin,
|
|
24
|
+
validate_data_url,
|
|
25
|
+
)
|
|
20
26
|
from openepd.model.declaration import (
|
|
21
27
|
DEVELOPER_DESCRIPTION,
|
|
22
28
|
PROGRAM_OPERATOR_DESCRIPTION,
|
|
@@ -243,6 +249,11 @@ class EpdPreviewV0(
|
|
|
243
249
|
msg = "Invalid doctype"
|
|
244
250
|
raise ValueError(msg)
|
|
245
251
|
|
|
252
|
+
@pydantic.field_validator("product_usage_image", "manufacturing_image")
|
|
253
|
+
def validate_product_usage_image(cls, v: pydantic.AnyUrl | None) -> pydantic.AnyUrl | None:
|
|
254
|
+
validate_data_url(v, DATA_URL_IMAGE_MAX_LENGTH)
|
|
255
|
+
return v
|
|
256
|
+
|
|
246
257
|
|
|
247
258
|
EpdPreview = EpdPreviewV0
|
|
248
259
|
|
openepd/model/org.py
CHANGED
|
@@ -13,26 +13,22 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
|
-
import
|
|
17
|
-
import re
|
|
18
|
-
from typing import Any, Final, Optional
|
|
16
|
+
from typing import Any, Optional
|
|
19
17
|
|
|
20
18
|
from openlocationcode import openlocationcode
|
|
21
19
|
import pydantic
|
|
22
20
|
from pydantic import ConfigDict
|
|
23
21
|
|
|
24
22
|
from openepd.model.base import BaseOpenEpdSchema
|
|
25
|
-
from openepd.model.common import
|
|
23
|
+
from openepd.model.common import (
|
|
24
|
+
DATA_URL_IMAGE_MAX_LENGTH,
|
|
25
|
+
Location,
|
|
26
|
+
WithAltIdsMixin,
|
|
27
|
+
WithAttachmentsMixin,
|
|
28
|
+
validate_data_url,
|
|
29
|
+
)
|
|
26
30
|
from openepd.model.validation.common import ReferenceStr
|
|
27
31
|
|
|
28
|
-
ORG_LOGO_MAX_LENGTH: Final[int] = math.ceil(32 * 1024 * 4 / 3)
|
|
29
|
-
"""
|
|
30
|
-
Maximum length of Org.logo field.
|
|
31
|
-
|
|
32
|
-
Logo file size must be less than 32KB. Base64 encoding overhead (approximately 33%) requires
|
|
33
|
-
limiting the encoded string length to 4/3 of the file size limit.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
32
|
|
|
37
33
|
class OrgRef(BaseOpenEpdSchema):
|
|
38
34
|
"""Represents Organisation with minimal data."""
|
|
@@ -142,12 +138,7 @@ class Org(WithAttachmentsMixin, WithAltIdsMixin, OrgRef):
|
|
|
142
138
|
|
|
143
139
|
@pydantic.field_validator("logo")
|
|
144
140
|
def _validate_logo(cls, v: pydantic.AnyUrl | None) -> pydantic.AnyUrl | None:
|
|
145
|
-
|
|
146
|
-
msg = f"Logo URL must not exceed {ORG_LOGO_MAX_LENGTH} characters"
|
|
147
|
-
raise ValueError(msg)
|
|
148
|
-
if v and v.scheme == "data" and not re.compile(DATA_URL_REGEX).match(str(v)):
|
|
149
|
-
msg = "Invalid data URL format"
|
|
150
|
-
raise ValueError(msg)
|
|
141
|
+
validate_data_url(v, DATA_URL_IMAGE_MAX_LENGTH)
|
|
151
142
|
return v
|
|
152
143
|
|
|
153
144
|
|
|
@@ -232,6 +223,10 @@ class Plant(PlantRef, WithAttachmentsMixin, WithAltIdsMixin):
|
|
|
232
223
|
msg = "Incorrect pluscode for plant"
|
|
233
224
|
raise ValueError(msg)
|
|
234
225
|
|
|
226
|
+
if not openlocationcode.isFull(pluscode):
|
|
227
|
+
msg = "Passed Open Location Code is not a valid full code"
|
|
228
|
+
raise ValueError(msg)
|
|
229
|
+
|
|
235
230
|
if not web_domain:
|
|
236
231
|
msg = "Incorrect web_domain for plant"
|
|
237
232
|
raise ValueError(msg)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
openepd/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
|
|
2
|
-
openepd/__version__.py,sha256=
|
|
2
|
+
openepd/__version__.py,sha256=4_OOwkPWzDgb1S9aW43U_I7XLkBn0l8_JXtmi6r1ghA,639
|
|
3
3
|
openepd/api/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
|
|
4
4
|
openepd/api/average_dataset/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
|
|
5
5
|
openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=mjTT8eGtfj6Fgp-wcs0cCWA7DJo1KL_iQ75rgKkaY3c,8037
|
|
@@ -43,15 +43,15 @@ openepd/m49/utils.py,sha256=0UvdtC9gtvRA5WT_hJDIuQR0RSrnx-S34wwwBRM_tsM,7807
|
|
|
43
43
|
openepd/model/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dvvtd4,620
|
|
44
44
|
openepd/model/base.py,sha256=EVmSzFqIiHQuKODJw_xncYGLy8T9p895MRZdkaeK4Fo,13648
|
|
45
45
|
openepd/model/category.py,sha256=iyzzAsiVwW4zJ61oYsm9Sy-sEBA71-aMFXcJP1Y-dPI,1734
|
|
46
|
-
openepd/model/common.py,sha256=
|
|
47
|
-
openepd/model/declaration.py,sha256=
|
|
48
|
-
openepd/model/epd.py,sha256=
|
|
46
|
+
openepd/model/common.py,sha256=L-nOsl4MmfSMFOehDyJaltwww--W-MR278-F4iVoVic,15924
|
|
47
|
+
openepd/model/declaration.py,sha256=5uNk2y8bJo0DfsCWdDf4F2YkN0RGeiApAA3oZ67uO-0,15194
|
|
48
|
+
openepd/model/epd.py,sha256=N7dzxfgEOvuNOHatr3_KvwRatVJXQ4mHKTbh7FCUrC0,13077
|
|
49
49
|
openepd/model/factory.py,sha256=UWSGpfCr3GiMTP4rzBkwqxzbXB6GKZ_5Okb1Dqa_4aA,2701
|
|
50
50
|
openepd/model/generic_estimate.py,sha256=_R18Uz-hvxtSBl53D0_OkwVCWvoa2nIDjBdec6vEPDE,4304
|
|
51
51
|
openepd/model/geography.py,sha256=Jx7NIDdk_sIvwyh-7YxnIjAwIHW2HCQK7UtFGM2xKtw,42095
|
|
52
52
|
openepd/model/industry_epd.py,sha256=Cqn01IUNSZqRkyU05TwtOLXDKlg0YnGzqvKL8A__zbI,4061
|
|
53
53
|
openepd/model/lcia.py,sha256=6o6GNwLaQaWyYAXCnHl2aAgDa12_v7DwpME5BfVMezk,32780
|
|
54
|
-
openepd/model/org.py,sha256=
|
|
54
|
+
openepd/model/org.py,sha256=1THgP8vLuXEWsHkYDT4k-mdSQ1vKiF9Y4AjNKq0Og_4,9016
|
|
55
55
|
openepd/model/pcr.py,sha256=cu3EakCAjBCkcb_AaLXB-xEjY0mlG-wJe74zGc5tdS0,5637
|
|
56
56
|
openepd/model/specs/README.md,sha256=UGhSiFJ9hOxT1mZl-5ZrhkOrPKf1W_gcu5CI9hzV7LU,2430
|
|
57
57
|
openepd/model/specs/__init__.py,sha256=-3uaImbGfOkRdpHQkhHe0eimAg0UBntR3WiT21Pmt1I,3837
|
|
@@ -156,7 +156,7 @@ openepd/utils/mapping/__init__.py,sha256=9THJcV3LT7JDBOMz1px-QFf_sdJ0LOqJ5dmA9Dv
|
|
|
156
156
|
openepd/utils/mapping/common.py,sha256=hxfN-WW2WLwE_agQzf_mhvz6OHq5WWlr24uZ1S81k4Y,8426
|
|
157
157
|
openepd/utils/mapping/geography.py,sha256=1_-dvLk11Hqn-K58yUI5pQ5X5gsnJPFlFT7JK2Rdoeg,2396
|
|
158
158
|
openepd/utils/markdown.py,sha256=RQmudPhb4QU1I4-S-VV2WFbzzq2Po09kbpjjKbwkA9E,1830
|
|
159
|
-
openepd-7.
|
|
160
|
-
openepd-7.
|
|
161
|
-
openepd-7.
|
|
162
|
-
openepd-7.
|
|
159
|
+
openepd-7.14.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
160
|
+
openepd-7.14.0.dist-info/METADATA,sha256=gKmM-w5poyAM8GYRAytiMrIIFQ42fVmXeyrXj32qCJw,9811
|
|
161
|
+
openepd-7.14.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
162
|
+
openepd-7.14.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|