openepd 6.31.1__tar.gz → 6.32.0__tar.gz

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 (164) hide show
  1. {openepd-6.31.1 → openepd-6.32.0}/PKG-INFO +1 -1
  2. {openepd-6.31.1 → openepd-6.32.0}/pyproject.toml +1 -1
  3. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/__version__.py +1 -1
  4. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/base.py +1 -1
  5. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/common.py +25 -2
  6. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/declaration.py +2 -14
  7. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/epd.py +15 -3
  8. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/org.py +14 -14
  9. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/masonry.py +0 -10
  10. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/validation/quantity.py +1 -1
  11. {openepd-6.31.1 → openepd-6.32.0}/LICENSE +0 -0
  12. {openepd-6.31.1 → openepd-6.32.0}/README.md +0 -0
  13. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/__init__.py +0 -0
  14. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/__init__.py +0 -0
  15. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/average_dataset/__init__.py +0 -0
  16. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/average_dataset/generic_estimate_sync_api.py +0 -0
  17. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/average_dataset/industry_epd_sync_api.py +0 -0
  18. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/base_sync_client.py +0 -0
  19. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/category/__init__.py +0 -0
  20. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/category/dto.py +0 -0
  21. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/category/sync_api.py +0 -0
  22. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/common.py +0 -0
  23. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/dto/__init__.py +0 -0
  24. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/dto/base.py +0 -0
  25. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/dto/common.py +0 -0
  26. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/dto/meta.py +0 -0
  27. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/dto/mf.py +0 -0
  28. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/dto/params.py +0 -0
  29. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/epd/__init__.py +0 -0
  30. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/epd/dto.py +0 -0
  31. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/epd/sync_api.py +0 -0
  32. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/errors.py +0 -0
  33. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/org/__init__.py +0 -0
  34. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/org/sync_api.py +0 -0
  35. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/pcr/__init__.py +0 -0
  36. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/pcr/sync_api.py +0 -0
  37. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/plant/__init__.py +0 -0
  38. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/plant/sync_api.py +0 -0
  39. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/standard/__init__.py +0 -0
  40. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/standard/sync_api.py +0 -0
  41. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/sync_client.py +0 -0
  42. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/test/__init__.py +0 -0
  43. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/api/utils.py +0 -0
  44. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/bundle/__init__.py +0 -0
  45. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/bundle/base.py +0 -0
  46. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/bundle/model.py +0 -0
  47. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/bundle/reader.py +0 -0
  48. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/bundle/writer.py +0 -0
  49. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/compat/__init__.py +0 -0
  50. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/compat/compat_functional_validators.py +0 -0
  51. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/compat/pydantic.py +0 -0
  52. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/constants/__init__.py +0 -0
  53. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/constants/scope_phases.py +0 -0
  54. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/m49/__init__.py +0 -0
  55. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/m49/const.py +0 -0
  56. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/m49/utils.py +0 -0
  57. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/__init__.py +0 -0
  58. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/category.py +0 -0
  59. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/factory.py +0 -0
  60. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/generic_estimate.py +0 -0
  61. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/geography.py +0 -0
  62. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/industry_epd.py +0 -0
  63. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/lcia.py +0 -0
  64. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/pcr.py +0 -0
  65. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/README.md +0 -0
  66. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/__init__.py +0 -0
  67. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/asphalt.py +0 -0
  68. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/base.py +0 -0
  69. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/concrete.py +0 -0
  70. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/enums.py +0 -0
  71. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/__init__.py +0 -0
  72. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/accessories.py +0 -0
  73. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/aggregates.py +0 -0
  74. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/aluminium.py +0 -0
  75. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/asphalt.py +0 -0
  76. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/bulk_materials.py +0 -0
  77. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/cast_decks_and_underlayment.py +0 -0
  78. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/cladding.py +0 -0
  79. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/cmu.py +0 -0
  80. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/concrete.py +0 -0
  81. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/conveying_equipment.py +0 -0
  82. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/electrical.py +0 -0
  83. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/electrical_transmission_and_distribution_equipment.py +0 -0
  84. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/electricity.py +0 -0
  85. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/exterior_improvements.py +0 -0
  86. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/finishes.py +0 -0
  87. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/fire_and_smoke_protection.py +0 -0
  88. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/furnishings.py +0 -0
  89. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/grouting.py +0 -0
  90. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/manufacturing_inputs.py +0 -0
  91. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/masonry.py +0 -0
  92. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/material_handling.py +0 -0
  93. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/mechanical.py +0 -0
  94. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/mechanical_insulation.py +0 -0
  95. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/mixins/__init__.py +0 -0
  96. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/mixins/access_flooring_mixin.py +0 -0
  97. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/network_infrastructure.py +0 -0
  98. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/non_construction.py +0 -0
  99. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/openings.py +0 -0
  100. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/other_electrical_equipment.py +0 -0
  101. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/other_materials.py +0 -0
  102. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/plumbing.py +0 -0
  103. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/precast_concrete.py +0 -0
  104. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/sheathing.py +0 -0
  105. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/steel.py +0 -0
  106. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/thermal_moisture_protection.py +0 -0
  107. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/utility_piping.py +0 -0
  108. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/wood.py +0 -0
  109. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/range/wood_joists.py +0 -0
  110. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/__init__.py +0 -0
  111. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/accessories.py +0 -0
  112. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/aggregates.py +0 -0
  113. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/aluminium.py +0 -0
  114. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/asphalt.py +0 -0
  115. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/bulk_materials.py +0 -0
  116. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/cast_decks_and_underlayment.py +0 -0
  117. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/cladding.py +0 -0
  118. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/cmu.py +0 -0
  119. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/common.py +0 -0
  120. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/concrete.py +0 -0
  121. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/conveying_equipment.py +0 -0
  122. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/deprecated/__init__.py +0 -0
  123. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/deprecated/concrete.py +0 -0
  124. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/deprecated/steel.py +0 -0
  125. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/electrical.py +0 -0
  126. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/electrical_transmission_and_distribution_equipment.py +0 -0
  127. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/electricity.py +0 -0
  128. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/exterior_improvements.py +0 -0
  129. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/finishes.py +0 -0
  130. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/fire_and_smoke_protection.py +0 -0
  131. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/furnishings.py +0 -0
  132. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/grouting.py +0 -0
  133. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/manufacturing_inputs.py +0 -0
  134. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/material_handling.py +0 -0
  135. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/mechanical.py +0 -0
  136. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/mechanical_insulation.py +0 -0
  137. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/mixins/__init__.py +0 -0
  138. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/mixins/access_flooring_mixin.py +0 -0
  139. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/mixins/conduit_mixin.py +0 -0
  140. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/network_infrastructure.py +0 -0
  141. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/non_construction.py +0 -0
  142. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/openings.py +0 -0
  143. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/other_electrical_equipment.py +0 -0
  144. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/other_materials.py +0 -0
  145. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/plumbing.py +0 -0
  146. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/precast_concrete.py +0 -0
  147. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/sheathing.py +0 -0
  148. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/steel.py +0 -0
  149. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/thermal_moisture_protection.py +0 -0
  150. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/utility_piping.py +0 -0
  151. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/wood.py +0 -0
  152. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/specs/singular/wood_joists.py +0 -0
  153. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/standard.py +0 -0
  154. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/validation/__init__.py +0 -0
  155. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/validation/common.py +0 -0
  156. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/validation/enum.py +0 -0
  157. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/validation/numbers.py +0 -0
  158. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/model/versioning.py +0 -0
  159. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/patch_pydantic.py +0 -0
  160. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/py.typed +0 -0
  161. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/utils/__init__.py +0 -0
  162. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/utils/functional.py +0 -0
  163. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/utils/mapping/__init__.py +0 -0
  164. {openepd-6.31.1 → openepd-6.32.0}/src/openepd/utils/mapping/common.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openepd
3
- Version: 6.31.1
3
+ Version: 6.32.0
4
4
  Summary: Python library to work with OpenEPD format
5
5
  License: Apache-2.0
6
6
  Author: C-Change Labs
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openepd"
3
- version = "6.31.1"
3
+ version = "6.32.0"
4
4
  license = "Apache-2.0"
5
5
  description = "Python library to work with OpenEPD format"
6
6
  authors = ["C-Change Labs <support@c-change-labs.com>"]
@@ -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 = "6.31.1"
16
+ VERSION = "6.32.0"
@@ -70,7 +70,7 @@ class BaseOpenEpdSchema(pyd.BaseModel):
70
70
  allow_mutation = True
71
71
  validate_assignment = False
72
72
  allow_population_by_field_name = True
73
- use_enum_values = True
73
+ use_enum_values = False
74
74
  schema_extra: Callable | dict = modify_pydantic_schema
75
75
 
76
76
  def to_serializable(self, *args, **kwargs) -> dict[str, Any]:
@@ -15,14 +15,15 @@
15
15
  #
16
16
  from collections.abc import Callable, Generator
17
17
  from enum import StrEnum
18
+ import math
18
19
  import re
19
- from typing import Annotated, Any
20
+ from typing import Annotated, Any, Final
20
21
 
21
22
  from openepd.compat.pydantic import pyd
22
23
  from openepd.model.base import BaseOpenEpdSchema
23
24
  from openepd.model.validation.numbers import RatioFloat
24
25
 
25
- DATA_URL_REGEX = r"^data:([-\w]+\/[-+\w.]+)?(;?\w+=[-\w]+)*(;base64)?,.*$"
26
+ DATA_URL_REGEX = r"^data:([-\w]+\/[-+\w.]+)?(;?\w+=[-\w]+)*(;base64)?,(.*)$"
26
27
  """
27
28
  Regular expression pattern for matching Data URLs.
28
29
 
@@ -31,6 +32,14 @@ in web pages as if they were external resources.
31
32
  The pattern matches the following format: data:[<media-type>][;base64],<data>
32
33
  """
33
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
+
34
43
 
35
44
  class Amount(BaseOpenEpdSchema):
36
45
  """A value-and-unit pairing for amounts that do not have an uncertainty."""
@@ -336,3 +345,17 @@ class DataUrl(str):
336
345
  raise ValueError(msg)
337
346
 
338
347
  yield validator
348
+
349
+
350
+ def validate_data_url(v: str | None, max_length: int) -> None:
351
+ """
352
+ Validate max length of data URL.
353
+
354
+ :param v: data URL string.
355
+ :param max_length: maximum allowed length.
356
+ :raises ValueError: if the data URL exceeds the maximum length.
357
+ :return: None
358
+ """
359
+ if v and len(v) > max_length:
360
+ msg = f"URL must not exceed {max_length} characters"
361
+ raise ValueError(msg)
@@ -16,12 +16,10 @@
16
16
  import abc
17
17
  import datetime
18
18
  from enum import StrEnum
19
- import math
20
- from typing import Final
21
19
 
22
20
  from openepd.compat.pydantic import pyd
23
21
  from openepd.model.base import BaseOpenEpdSchema, OpenXpdUUID, RootDocument
24
- from openepd.model.common import Amount, DataUrl
22
+ from openepd.model.common import DATA_URL_IMAGE_MAX_LENGTH, Amount, DataUrl, validate_data_url
25
23
  from openepd.model.geography import Geography
26
24
  from openepd.model.org import Org
27
25
  from openepd.model.pcr import Pcr
@@ -34,14 +32,6 @@ DEVELOPER_DESCRIPTION = "The organization responsible for the underlying LCA (an
34
32
  PROGRAM_OPERATOR_DESCRIPTION = "JSON object for program operator Org"
35
33
  THIRD_PARTY_VERIFIER_DESCRIPTION = "JSON object for Org that performed a critical review of the EPD data"
36
34
 
37
- PRODUCT_IMAGE_MAX_LENGTH: Final[int] = math.ceil(32 * 1024 * 4 / 3)
38
- """
39
- Maximum length for product_image, product_image_small fields.
40
-
41
- Image file size must be less than 32KB. Base64 encoding overhead (approximately 33%) requires
42
- limiting the encoded string length to 4/3 of the file size limit.
43
- """
44
-
45
35
 
46
36
  class BaseDeclaration(RootDocument, abc.ABC):
47
37
  """Base class for declaration-related documents (EPDs, Industry-wide EPDs, Generic Estimates)."""
@@ -175,9 +165,7 @@ class BaseDeclaration(RootDocument, abc.ABC):
175
165
 
176
166
  @pyd.validator("product_image", "product_image_small")
177
167
  def validate_product_image(cls, v: str | None) -> str | None:
178
- if v and len(v) > PRODUCT_IMAGE_MAX_LENGTH:
179
- msg = f"URL must not exceed {PRODUCT_IMAGE_MAX_LENGTH} characters"
180
- raise ValueError(msg)
168
+ validate_data_url(v, DATA_URL_IMAGE_MAX_LENGTH)
181
169
  return v
182
170
 
183
171
 
@@ -16,7 +16,14 @@
16
16
 
17
17
  from openepd.compat.pydantic import pyd
18
18
  from openepd.model.base import BaseDocumentFactory, OpenEpdDoctypes, OpenEpdExtension
19
- from openepd.model.common import Ingredient, WithAltIdsMixin, WithAttachmentsMixin
19
+ from openepd.model.common import (
20
+ DATA_URL_IMAGE_MAX_LENGTH,
21
+ DataUrl,
22
+ Ingredient,
23
+ WithAltIdsMixin,
24
+ WithAttachmentsMixin,
25
+ validate_data_url,
26
+ )
20
27
  from openepd.model.declaration import (
21
28
  DEVELOPER_DESCRIPTION,
22
29
  PROGRAM_OPERATOR_DESCRIPTION,
@@ -200,14 +207,14 @@ class EpdPreviewV0(
200
207
  description="Text description of how product is typically used. Can be used to describe accessories "
201
208
  "like fasteners, adhesives, etc. Supports plain text or github flavored markdown.",
202
209
  )
203
- product_usage_image: pyd.AnyUrl | None = pyd.Field(
210
+ product_usage_image: pyd.AnyUrl | None | DataUrl = pyd.Field(
204
211
  description="Pointer (url) to image illustrating how the product is used. No more than 10MB.", default=None
205
212
  )
206
213
  manufacturing_description: str | None = pyd.Field(
207
214
  default=None,
208
215
  description="Text description of manufacturing process. Supports plain text or github flavored markdown.",
209
216
  )
210
- manufacturing_image: pyd.AnyUrl | None = pyd.Field(
217
+ manufacturing_image: pyd.AnyUrl | None | DataUrl = pyd.Field(
211
218
  description="Pointer (url) to an image illustrating the manufacturing process. No more than 10MB.", default=None
212
219
  )
213
220
 
@@ -235,6 +242,11 @@ class EpdPreviewV0(
235
242
  msg = "Invalid doctype"
236
243
  raise ValueError(msg)
237
244
 
245
+ @pyd.validator("product_usage_image", "manufacturing_image")
246
+ def validate_product_image(cls, v: str | None) -> str | None:
247
+ validate_data_url(v, DATA_URL_IMAGE_MAX_LENGTH)
248
+ return v
249
+
238
250
 
239
251
  EpdPreview = EpdPreviewV0
240
252
 
@@ -13,24 +13,22 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- import math
17
- from typing import Annotated, Final, Optional
16
+ from typing import Annotated, Optional
18
17
 
19
18
  from openlocationcode import openlocationcode
20
19
 
21
20
  from openepd.compat.pydantic import pyd
22
21
  from openepd.model.base import BaseOpenEpdSchema
23
- from openepd.model.common import DataUrl, Location, WithAltIdsMixin, WithAttachmentsMixin
22
+ from openepd.model.common import (
23
+ DATA_URL_IMAGE_MAX_LENGTH,
24
+ DataUrl,
25
+ Location,
26
+ WithAltIdsMixin,
27
+ WithAttachmentsMixin,
28
+ validate_data_url,
29
+ )
24
30
  from openepd.model.validation.common import ReferenceStr
25
31
 
26
- ORG_LOGO_MAX_LENGTH: Final[int] = math.ceil(32 * 1024 * 4 / 3)
27
- """
28
- Maximum length of Org.logo field.
29
-
30
- Logo file size must be less than 32KB. Base64 encoding overhead (approximately 33%) requires
31
- limiting the encoded string length to 4/3 of the file size limit.
32
- """
33
-
34
32
 
35
33
  class OrgRef(BaseOpenEpdSchema):
36
34
  """Represents Organisation with minimal data."""
@@ -105,9 +103,7 @@ class Org(WithAttachmentsMixin, WithAltIdsMixin, OrgRef):
105
103
 
106
104
  @pyd.validator("logo")
107
105
  def validate_logo(cls, v: str | None) -> str | None:
108
- if v and len(v) > ORG_LOGO_MAX_LENGTH:
109
- msg = f"Logo URL must not exceed {ORG_LOGO_MAX_LENGTH} characters"
110
- raise ValueError(msg)
106
+ validate_data_url(v, DATA_URL_IMAGE_MAX_LENGTH)
111
107
  return v
112
108
 
113
109
 
@@ -179,6 +175,10 @@ class Plant(PlantRef, WithAttachmentsMixin, WithAltIdsMixin):
179
175
  msg = "Incorrect pluscode for plant"
180
176
  raise ValueError(msg)
181
177
 
178
+ if not openlocationcode.isFull(pluscode):
179
+ msg = "Passed Open Location Code is not a valid full code"
180
+ raise ValueError(msg)
181
+
182
182
  if not web_domain:
183
183
  msg = "Incorrect web_domain for plant"
184
184
  raise ValueError(msg)
@@ -18,8 +18,6 @@ from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
18
18
  from openepd.model.validation.quantity import (
19
19
  PressureMPaStr,
20
20
  ThermalConductivityStr,
21
- validate_quantity_ge_factory,
22
- validate_quantity_unit_factory,
23
21
  )
24
22
 
25
23
 
@@ -41,14 +39,6 @@ class AutoclavedAeratedConcreteV1(BaseOpenEpdHierarchicalSpec):
41
39
  )
42
40
  white: bool | None = pyd.Field(default=None, description="", example=True)
43
41
 
44
- _aac_thermal_conductivity_is_quantity_validator = pyd.validator("thermal_conductivity", allow_reuse=True)(
45
- validate_quantity_unit_factory("W / (m * K)")
46
- )
47
-
48
- _aac_thermal_conductivity_min_validator = pyd.validator("thermal_conductivity", allow_reuse=True)(
49
- validate_quantity_ge_factory("0 W / (m * K)")
50
- )
51
-
52
42
 
53
43
  class BrickV1(BaseOpenEpdHierarchicalSpec):
54
44
  """Solid masonry units made from clay or shale."""
@@ -317,7 +317,7 @@ class AreaPerVolumeStr(QuantityStr):
317
317
  class ThermalConductivityStr(QuantityStr):
318
318
  """Thermal conductivity quantity type."""
319
319
 
320
- unit = "1 W / K / m"
320
+ unit = "W / K / m"
321
321
 
322
322
 
323
323
  class ThermalExpansionStr(QuantityStr):
File without changes
File without changes
File without changes