openepd 2.0.0__py3-none-any.whl → 3.1.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 (95) 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 +72 -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 +288 -24
  46. openepd/model/specs/generated/accessories.py +63 -0
  47. openepd/model/specs/generated/aggregates.py +71 -0
  48. openepd/model/specs/generated/aluminium.py +66 -0
  49. openepd/model/specs/generated/asphalt.py +86 -0
  50. openepd/model/specs/generated/bulk_materials.py +26 -0
  51. openepd/model/specs/generated/cast_decks_and_underlayment.py +26 -0
  52. openepd/model/specs/generated/cladding.py +214 -0
  53. openepd/model/specs/generated/cmu.py +46 -0
  54. openepd/model/specs/generated/common.py +27 -0
  55. openepd/model/specs/generated/concrete.py +151 -0
  56. openepd/model/specs/generated/conveying_equipment.py +57 -0
  57. openepd/model/specs/generated/electrical.py +297 -0
  58. openepd/model/specs/generated/electrical_transmission_and_distribution_equipment.py +63 -0
  59. openepd/model/specs/generated/electricity.py +26 -0
  60. openepd/model/specs/generated/enums.py +2420 -0
  61. openepd/model/specs/generated/finishes.py +519 -0
  62. openepd/model/specs/generated/fire_and_smoke_protection.py +79 -0
  63. openepd/model/specs/generated/furnishings.py +95 -0
  64. openepd/model/specs/generated/grouting.py +26 -0
  65. openepd/model/specs/generated/manufacturing_inputs.py +131 -0
  66. openepd/model/specs/generated/masonry.py +77 -0
  67. openepd/model/specs/generated/material_handling.py +35 -0
  68. openepd/model/specs/generated/mechanical.py +271 -0
  69. openepd/model/specs/generated/mechanical_insulation.py +41 -0
  70. openepd/model/specs/generated/network_infrastructure.py +181 -0
  71. openepd/model/specs/generated/openings.py +423 -0
  72. openepd/model/specs/generated/other_electrical_equipment.py +26 -0
  73. openepd/model/specs/generated/other_materials.py +123 -0
  74. openepd/model/specs/generated/plumbing.py +153 -0
  75. openepd/model/specs/generated/precast_concrete.py +68 -0
  76. openepd/model/specs/generated/sheathing.py +74 -0
  77. openepd/model/specs/generated/steel.py +224 -0
  78. openepd/model/specs/generated/thermal_moisture_protection.py +233 -0
  79. openepd/model/specs/generated/utility_piping.py +65 -0
  80. openepd/model/specs/generated/wood.py +167 -0
  81. openepd/model/specs/generated/wood_joists.py +38 -0
  82. openepd/model/specs/glass.py +360 -0
  83. openepd/model/specs/steel.py +184 -0
  84. openepd/model/specs/wood.py +130 -0
  85. openepd/model/standard.py +2 -3
  86. openepd/model/validation/__init__.py +19 -0
  87. openepd/model/validation/common.py +59 -0
  88. openepd/model/validation/numbers.py +26 -0
  89. openepd/model/validation/quantity.py +132 -0
  90. openepd/model/versioning.py +129 -0
  91. {openepd-2.0.0.dist-info → openepd-3.1.0.dist-info}/METADATA +36 -5
  92. openepd-3.1.0.dist-info/RECORD +95 -0
  93. openepd-2.0.0.dist-info/RECORD +0 -22
  94. {openepd-2.0.0.dist-info → openepd-3.1.0.dist-info}/LICENSE +0 -0
  95. {openepd-2.0.0.dist-info → openepd-3.1.0.dist-info}/WHEEL +0 -0
@@ -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,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 typing import Annotated, Any, Callable, Type, TypeAlias
21
+
22
+ from openepd.compat.pydantic import pyd
23
+ from openepd.model.versioning import Version
24
+
25
+
26
+ def together_validator(field1: str, field2: Any, values: dict[str, Any]) -> Any:
27
+ """Shared validator to ensure that two fields are provided together or not provided at all."""
28
+ value1 = values.get(field1)
29
+ value2 = values.get(field2)
30
+ if value1 is not None and value2 is None or value1 is None and value2 is not None:
31
+ raise ValueError(f"Both or neither {field1} and {field2} days must be provided together")
32
+
33
+
34
+ def validate_version_format(v: str) -> str:
35
+ """Ensure that the extension version is valid."""
36
+ Version.parse_version(v) # will raise an error if not valid
37
+ return v
38
+
39
+
40
+ def validate_version_compatibility(class_version_attribute_name: str) -> Callable[[Type, str], str]:
41
+ """Ensure that the object which is passed for parsing and validation is compatible with the class."""
42
+
43
+ # we need closure to pass property name, since actual class will only be available in runtime
44
+ def internal_validate_version_compatibility(cls: Type, v: str) -> str:
45
+ if not hasattr(cls, class_version_attribute_name):
46
+ raise ValueError(f"Class {cls} must declare a class var extension var named {class_version_attribute_name}")
47
+
48
+ class_version = getattr(cls, class_version_attribute_name)
49
+ if Version.parse_version(v).major != Version.parse_version(class_version).major:
50
+ raise ValueError(f"Extension version {v} does not match class version {class_version}")
51
+ return v
52
+
53
+ return internal_validate_version_compatibility
54
+
55
+
56
+ ReferenceStr: TypeAlias = Annotated[
57
+ str,
58
+ pyd.Field(description="Reference to another object", example="https://buildingtransparency.org/ec3/epds/1u7zsed8"),
59
+ ]
@@ -0,0 +1,26 @@
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 Annotated
21
+
22
+ from openepd.compat.pydantic import pyd
23
+
24
+ # todo when move to pydantic 2, check that validators are being enforced.
25
+ RatioFloat = Annotated[float, pyd.Field(ge=0, le=1, example=0.5)]
26
+ PositiveInt = Annotated[int, pyd.Field(ge=0, example=1)]
@@ -0,0 +1,132 @@
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 abc import ABC, abstractmethod
21
+ from typing import TYPE_CHECKING, Annotated, Callable, TypeAlias
22
+
23
+ from openepd.compat.pydantic import pyd
24
+ from openepd.model.common import OpenEPDUnit
25
+
26
+ if TYPE_CHECKING:
27
+ from openepd.model.specs.base import BaseOpenEpdHierarchicalSpec
28
+
29
+ QuantityValidatorType = Callable[[type[BaseOpenEpdHierarchicalSpec], str], str]
30
+
31
+
32
+ class QuantityValidator(ABC):
33
+ """
34
+ Interface for quantity validator.
35
+
36
+ The openEPD models are mapped using the simple types. Caller code should provide their own implementation of this
37
+ and set it with `set_unit_validator` function.
38
+ """
39
+
40
+ @abstractmethod
41
+ def validate_unit_correctness(self, value: str, dimensionality: str) -> None:
42
+ """
43
+ Validate the given string value against the given dimensionality.
44
+
45
+ Args:
46
+ value: The value to validate, like "102.4 kg"
47
+ dimensionality: The dimensionality to validate against, like "kg"
48
+ Returns:
49
+ None if the value is valid, raises an error otherwise.
50
+ Raises:
51
+ ValueError: If the value is not valid.
52
+ """
53
+ pass
54
+
55
+ @abstractmethod
56
+ def validate_quantity_greater_or_equal(self, value: str, min_value: str) -> None:
57
+ """
58
+ Validate the quantity is greater than minimal value.
59
+
60
+ Args:
61
+ value: The value to validate, like "2.4 kg"
62
+ min_value: The value to compare with, like "102.4 kg"
63
+ Returns:
64
+ None if the value is valid, raises an error otherwise.
65
+ Raises:
66
+ ValueError: If the value is not valid.
67
+ """
68
+ pass
69
+
70
+ @abstractmethod
71
+ def validate_quantity_less_or_equal(self, value: str, max_value: str) -> None:
72
+ """
73
+ Validate the quantity is less than minimal value.
74
+
75
+ Args:
76
+ value: The value to validate, like "2.4 kg"
77
+ max_value: The value to compare with, like "0.4 kg"
78
+ Returns:
79
+ None if the value is valid, raises an error otherwise.
80
+ Raises:
81
+ ValueError: If the value is not valid.
82
+ """
83
+ pass
84
+
85
+
86
+ def validate_unit_factory(dimensionality: OpenEPDUnit | str) -> "QuantityValidatorType":
87
+ """Create validator for quantity field to check unit matching."""
88
+
89
+ def validator(cls: "type[BaseOpenEpdHierarchicalSpec]", value: str) -> str:
90
+ if hasattr(cls, "_QUANTITY_VALIDATOR") and cls._QUANTITY_VALIDATOR is not None:
91
+ cls._QUANTITY_VALIDATOR.validate_unit_correctness(value, dimensionality)
92
+ return value
93
+
94
+ return validator
95
+
96
+
97
+ def validate_quantity_ge_factory(min_value: str) -> "QuantityValidatorType":
98
+ """Create validator to check that quantity is greater than or equal to min_value."""
99
+
100
+ def validator(cls: "type[BaseOpenEpdHierarchicalSpec]", value: str) -> str:
101
+ if hasattr(cls, "_QUANTITY_VALIDATOR") and cls._QUANTITY_VALIDATOR is not None:
102
+ cls._QUANTITY_VALIDATOR.validate_quantity_greater_or_equal(value, min_value)
103
+ return value
104
+
105
+ return validator
106
+
107
+
108
+ def validate_quantity_le_factory(max_value: str) -> "QuantityValidatorType":
109
+ """Create validator to check that quantity is less than or equal to max_value."""
110
+
111
+ def validator(cls: "type[BaseOpenEpdHierarchicalSpec]", value: str) -> str:
112
+ if hasattr(cls, "_QUANTITY_VALIDATOR") and cls._QUANTITY_VALIDATOR is not None:
113
+ cls._QUANTITY_VALIDATOR.validate_quantity_less_or_equal(value, max_value)
114
+ return value
115
+
116
+ return validator
117
+
118
+
119
+ # todo with the migration to Pydantic 2 we will be able to use pydantic.funcational_validators.AfterDecorator
120
+ # this will let us bind the validator not to the model or the field, but to the type itself.
121
+
122
+ # for abitrary non-standard quantity
123
+ QuantityStr: TypeAlias = Annotated[str, pyd.Field()]
124
+ PressureMPaStr: TypeAlias = Annotated[str, pyd.Field(example="30 MPa")]
125
+ MassKgStr: TypeAlias = Annotated[str, pyd.Field(example="30 kg")]
126
+ AreaM2Str: TypeAlias = Annotated[str, pyd.Field(example="12 m2", gt=0)]
127
+ LengthMStr: TypeAlias = Annotated[str, pyd.Field(example="30 m", gt=0)]
128
+ LengthMmStr: TypeAlias = Annotated[str, pyd.Field(example="30 mm", gt=0)]
129
+ LengthInchStr: TypeAlias = Annotated[str, pyd.Field(example="30 m", gt=0)]
130
+ TemperatureCStr: TypeAlias = Annotated[str, pyd.Field(example="45 C")]
131
+ HeatConductanceUCIStr: TypeAlias = Annotated[str, pyd.Field(example="0.3 U")]
132
+ GwpKgCo2eStr: TypeAlias = Annotated[str, pyd.Field(example="300 kgCO2e")]
@@ -0,0 +1,129 @@
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 abc import ABC
21
+ from enum import ReprEnum
22
+ from typing import ClassVar, NamedTuple
23
+
24
+ from openepd.compat.pydantic import pyd
25
+
26
+
27
+ class WithExtVersionMixin(ABC, pyd.BaseModel):
28
+ """Mixin for extensions supporting versions: recommended way."""
29
+
30
+ _EXT_VERSION: ClassVar[str]
31
+ """Exact version (major, minor) of the spec extension"""
32
+
33
+ def __init_subclass__(cls):
34
+ """Set the default value for the ext_version field from _EXT_VERSION class var."""
35
+ super().__init_subclass__()
36
+ if hasattr(cls, "_EXT_VERSION"):
37
+ cls.__fields__["ext_version"].default = cls._EXT_VERSION
38
+
39
+ # Note: default is set programmatically in __init_subclass__
40
+ ext_version: str | None = pyd.Field(description="Extension version", example="3.22", default=None)
41
+
42
+
43
+ class Version(NamedTuple):
44
+ """Version of the object or specification."""
45
+
46
+ major: int
47
+ minor: int
48
+
49
+ @staticmethod
50
+ def parse_version(version: str) -> "Version":
51
+ """Parse the version of extension or the format.
52
+
53
+ Version is expected to be major.minor
54
+
55
+ :param version: The extension version.
56
+ :return: A tuple of major and minor version numbers.
57
+ """
58
+ splits = version.split(".", 1) if isinstance(version, str) else None
59
+ if len(splits) != 2:
60
+ raise ValueError(f"Invalid version: {version}")
61
+ if not splits[0].isdigit() or not splits[1].isdigit():
62
+ raise ValueError(f"Invalid version: {version}")
63
+ return Version(major=int(splits[0]), minor=int(splits[1]))
64
+
65
+ def __str__(self) -> str:
66
+ return self.as_str()
67
+
68
+ def __repr__(self) -> str:
69
+ return f"[Version] {self.as_str()}"
70
+
71
+ def as_str(self) -> str:
72
+ """Return the version as a string."""
73
+ return f"{self.major}.{self.minor}"
74
+
75
+
76
+ class OpenEpdVersions(Version, ReprEnum):
77
+ """
78
+ Enum of supported openEPD versions.
79
+
80
+ When adding a new version - make sure to add a new major version to the list of supported versions.
81
+ When doing non-breaking change - update minor version in a corresponding enum value.
82
+ """
83
+
84
+ Version0 = Version(major=0, minor=1)
85
+
86
+ @classmethod
87
+ def get_supported_versions(cls) -> list[Version]:
88
+ """Return a list of supported versions."""
89
+ return [x.value for x in cls]
90
+
91
+ @classmethod
92
+ def supported_versions_str(cls, major_only: bool = False) -> str:
93
+ """
94
+ Return a comma separated list of the supported versions.
95
+
96
+ This is a utility method, might be helpful for logging, building error messages, etc.
97
+
98
+ :param major_only: If True, minor component will be replaced with 'x'. E.g. `2.x` instead of `2.1`
99
+ """
100
+ if major_only:
101
+ return ", ".join(f"{x.major}.x" for x in cls.get_supported_versions())
102
+ return ", ".join(str(x) for x in cls.get_supported_versions())
103
+
104
+ @classmethod
105
+ def get_most_recent_version(cls, branch: int | None = 0) -> Version:
106
+ """
107
+ Return the most recent version of the openEPD format.
108
+
109
+ If branch is specified - returns the most recent version of the specified branch, otherwise returns
110
+ the most recent version among all branches.
111
+ """
112
+ if branch is None:
113
+ highest: Version = max(cls, key=lambda x: x.value.major) # type: ignore
114
+ if highest:
115
+ return highest
116
+ for x in cls:
117
+ if x.value.major == branch:
118
+ return x.value
119
+ raise ValueError(
120
+ f"No version {branch}.x is not supported. Supported versions are: {', '.join(str(x.value) for x in cls)}"
121
+ )
122
+
123
+ @classmethod
124
+ def get_current(cls) -> Version:
125
+ """Return the most recent stable version of the format."""
126
+ return cls.get_most_recent_version()
127
+
128
+ def __repr__(self):
129
+ return f"[OpenEpdVesion] {self.name} - {self.value}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 2.0.0
3
+ Version: 3.1.0
4
4
  Summary: Python library to work with OpenEPD format
5
5
  Home-page: https://github.com/cchangelabs/openepd
6
6
  License: Apache-2.0
@@ -16,8 +16,10 @@ Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
- Requires-Dist: email-validator (>=1.3.0)
20
- Requires-Dist: pydantic (>=2.0,<3.0)
19
+ Provides-Extra: api-client
20
+ Requires-Dist: email-validator (>=1.3.1)
21
+ Requires-Dist: pydantic (>=1.10,<3.0)
22
+ Requires-Dist: requests (>=2.0) ; extra == "api-client"
21
23
  Project-URL: Repository, https://github.com/cchangelabs/openepd
22
24
  Description-Content-Type: text/markdown
23
25
 
@@ -57,18 +59,47 @@ documenting supply-chain specific data.
57
59
 
58
60
  ## Usage
59
61
 
62
+ ## Usage
63
+
60
64
  **❗ ATTENTION**: Pick the right version. The cornerstone of this library models package representing openEPD models.
61
65
  Models are defined with Pydantic library which is a dependency for openepd package. If you use Pydantic in your project
62
66
  carefully pick the version:
63
67
 
64
- * Use version below `1.0.0` if your project uses Pydantic version below `2.0.0`
65
- * Use version `1.0.0` or higher if your project uses Pydantic version `2.0.0` or above
68
+ * Use version **below** `2.0.0` if your project uses Pydantic version below `2.0.0`
69
+ * Use version `2.x.x` or higher if your project uses Pydantic version `2.0.0` or above
66
70
 
67
71
  ### Models
68
72
 
69
73
  The library provides the Pydantic models for all the OpenEPD entities. The models are available in the `openepd.models`
70
74
  module. For mode details on the usage please refer to Pydantic documentation.
71
75
 
76
+ ### API Client
77
+
78
+ The library provides the API client to work with the OpenEPD API. The client is available in the `openepd.client` module.
79
+ Currently, the only available implementation is based on synchronous [requests]() library. Client provides the following
80
+ features:
81
+ * Error handling - depending on HTTP status code the client raises different exceptions allowing to handle errors
82
+ in a more granular way.
83
+ * Throttling - the client is able to throttle the requests to the API to avoid hitting the rate limits.
84
+ * Retry - the client is able to retry the requests in case of the network errors.
85
+
86
+ #### API Client Usage
87
+
88
+ The following example illustrates the usage of the API client:
89
+
90
+ ```python
91
+ from openepd.api.sync_client import OpenEpdApiClientSync
92
+
93
+ # Setup the client
94
+ api_client = OpenEpdApiClientSync(
95
+ "https://openepd.buildingtransparency.org/api",
96
+ "<Your API Token>",
97
+ )
98
+
99
+ # Use API, e.g. get EPD by ID
100
+ epd = api_client.epds.get_by_openxpd_uuid("ec3b9j5t")
101
+ ```
102
+
72
103
  ### Bundle
73
104
 
74
105
  Bundle is a format which allows to bundle multiple openEPD objects together (it might be EPDs, PCRs, Orgs + any
@@ -0,0 +1,95 @@
1
+ openepd/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
2
+ openepd/__version__.py,sha256=MqTqfn60ULDejKjKIAtuxNQxkhxVa4jNydXkB3BvLEg,855
3
+ openepd/api/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
4
+ openepd/api/base_sync_client.py,sha256=JcNpWsGoIK_1Eg27CAQd7nIjbcfD56jQ1nS6B48Q0cI,21142
5
+ openepd/api/category/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
6
+ openepd/api/category/dto.py,sha256=oyeJp_F_55OVXfTX7EVl6VYrzA_STm4h-x52CW06ExQ,1067
7
+ openepd/api/category/sync_api.py,sha256=QLEyga590UON9zv7864NjdSPkxSoeWObIOCUOLhD9tc,1588
8
+ openepd/api/common.py,sha256=rfxjaDd7gGoen85wSooHt0W9xHdUlSlkTlkr2CO1ccg,8681
9
+ openepd/api/dto/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
10
+ openepd/api/dto/base.py,sha256=s4CivEzgMNG4WKZJoEt3vALVZNWk76soBCNtzr_AVL4,1250
11
+ openepd/api/dto/common.py,sha256=M5S0WphcRhaeJSP9jJY-IqNgLZIRSYmqvlNh_9fNFVY,4705
12
+ openepd/api/dto/meta.py,sha256=_rJ6pZtXyJmoaMhCZ1xnnCzp127LJ6RkayI4sdm6QYc,2377
13
+ openepd/api/dto/mf.py,sha256=ac1W0QPg9ndsUq_Rnv5E7HR0AZXuKSifBoJXo_I4zFE,2211
14
+ openepd/api/dto/params.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
15
+ openepd/api/epd/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
16
+ openepd/api/epd/dto.py,sha256=vFQURo9QzK5fcDNSjc4BlrK2KpkWbnxFle5jPMq-KTw,5091
17
+ openepd/api/epd/sync_api.py,sha256=JEZR3WBZHqP4yOk1qkWsz0oKHMgegoZ7Pvoh6YTVefg,4391
18
+ openepd/api/errors.py,sha256=K6L_T91iJLFSl_7hVS6poV_BUjZJe3qJBUzp8mItm7g,2376
19
+ openepd/api/pcr/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
20
+ openepd/api/pcr/dto.py,sha256=vjkxHzbBLrG9cDoaAbPOPSPjhIRI8z3XewI5wfry6Hk,1649
21
+ openepd/api/pcr/sync_api.py,sha256=j8g23-FuaN2JkROVRo32v77JWpTWDIOWnIyomBbqNd4,1805
22
+ openepd/api/sync_client.py,sha256=DBkoB8rH8OG1d1sJ77h2YvIP8aFQX5eCfaX4sTN0vEs,2504
23
+ openepd/api/test/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
24
+ openepd/bundle/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
25
+ openepd/bundle/base.py,sha256=wSmRp6IjWtOSoSBpK_OhrxJ2OgHu_2hNnwYS4mmNFSA,7086
26
+ openepd/bundle/model.py,sha256=TdFkUTOnd_dklcP-Qahp2glvk1YgEM0HfiqQz5MikeA,2663
27
+ openepd/bundle/reader.py,sha256=z4v_UWyaosktN3DdmnRx8GpLq4DkejjoUsckFfCgUac,6904
28
+ openepd/bundle/writer.py,sha256=AfvzzdAr9ybIbtiZfuX2mAGfddamTxXxUTxtHHrs2Gc,8353
29
+ openepd/compat/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
30
+ openepd/compat/pydantic.py,sha256=wh7vExwILD9QUYAKbrALXtTqNvsc6E8tjVVYXF2WvTY,1174
31
+ openepd/model/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
32
+ openepd/model/base.py,sha256=Yerebn3KP8-CdeeKOuQ1h16qkZnNGn7yvZNiAWutpsI,9154
33
+ openepd/model/category.py,sha256=NhQzKYi02DcdDy83qI_WZuGfYAUcZgsEPEXRa0nGqxs,1856
34
+ openepd/model/common.py,sha256=Uuc-Rbo89Xw89YWbiMtqggvWeFptbgNw6KWdZI8f7wg,5659
35
+ openepd/model/epd.py,sha256=WWWZU1c7HWkZZqkhUNMjyaHJYThboN6ZjmZ2L4UNM6I,14299
36
+ openepd/model/factory.py,sha256=qQZNb4yFN1EQWHHVS-fHnJ2gB-vsKz9hVmXXJE7YaRU,1918
37
+ openepd/model/lcia.py,sha256=MTNbNoTiZn_11XIx9m5D_iyTr0mnfIJYAyfnc1CHaSY,17165
38
+ openepd/model/org.py,sha256=XJcfKGPN90IIGcN-S1ZNy8Zh_yM28iT2wbJD3pk3T08,4013
39
+ openepd/model/pcr.py,sha256=MypmvAR56ldoSMqtq0JKVeqUGHD-heyfsOPXjGcZFQ4,4620
40
+ openepd/model/specs/README.md,sha256=W5LSMpZuW5x36cKS4HRfeFsClsRf8J9yHMMICghdc0s,862
41
+ openepd/model/specs/__init__.py,sha256=lN1u5WN1H9uwWSHb4sFEBxJ3_tvGYar9iCvsDD67JTQ,5176
42
+ openepd/model/specs/aluminium.py,sha256=wRtkixZqO_27mulz0m60oZfAR1I0r_4cikvT-9U4lnk,2271
43
+ openepd/model/specs/asphalt.py,sha256=1Vmw3jsdTyhPaM9ftIjMvpLj7GbGnZLytaJYDDJQ7bU,3549
44
+ openepd/model/specs/base.py,sha256=T0HsHTFf5ew1sLgUf-7dfifrMPMup7WRc-C5DHAXUc4,2697
45
+ openepd/model/specs/concrete.py,sha256=FnvzZw1VhOGgzqzuwu_F6Pu_c9Unovd4rzZWUu5KKMw,15655
46
+ openepd/model/specs/generated/accessories.py,sha256=Gt7H0Xz6kWce05MfF_J0v5sah8xrZnGcc7XhJBDkE30,1934
47
+ openepd/model/specs/generated/aggregates.py,sha256=TMw2f7K7kuKP23MWkeFyqKUIXJFIamwX3gSR-48k3AY,3161
48
+ openepd/model/specs/generated/aluminium.py,sha256=MXOo_Hnue2kbxg9nwF5d-C1rubqHACGjcJymGoRgUGU,2440
49
+ openepd/model/specs/generated/asphalt.py,sha256=D-V1J-VxjoAhfYA6ACnujLNGkAmqQ-RQRB4TEZeALpQ,3837
50
+ openepd/model/specs/generated/bulk_materials.py,sha256=DJgOjpj1ZqwwieMV_4wNKEgLnX1hKbAM4jaLDSICxNM,1034
51
+ openepd/model/specs/generated/cast_decks_and_underlayment.py,sha256=2VwwCgVRb3SuDy-x4EsI-n7GRnq0E7xrNE78CHoEExg,1058
52
+ openepd/model/specs/generated/cladding.py,sha256=RHq6irHwXJNnKuBOsA3h2g1jedMDOJPmV4WNjkdesgs,6939
53
+ openepd/model/specs/generated/cmu.py,sha256=mSRYG67m2c01C1dmYNyQjXQmYCcM4frpLQ3wKurTa50,2324
54
+ openepd/model/specs/generated/common.py,sha256=n_wuE-VtNFytpE-uLZrSXeeIIoNl2lSutPodiGKH94E,1117
55
+ openepd/model/specs/generated/concrete.py,sha256=cbTwYGxw0ttPYcg8zrkQEehNqtI3wakI7XgTEec0W24,6617
56
+ openepd/model/specs/generated/conveying_equipment.py,sha256=HcMSuyng9OlRKvUVYSstJx0XtaD8_cQ9ka8l4vG76AY,2422
57
+ openepd/model/specs/generated/electrical.py,sha256=oEhWkm4Au9N0xtTLUNTUVMxQUuJuvoLgOKccnAI0oGQ,10457
58
+ openepd/model/specs/generated/electrical_transmission_and_distribution_equipment.py,sha256=CiI6wcfo_tf6QoGkpAjUskCUKNJQvz0_N0RD7tF1oiA,2117
59
+ openepd/model/specs/generated/electricity.py,sha256=8W_vkCn_MDoB5rqGbPp2g04VMEG0ULMexD4OImgAt9U,1029
60
+ openepd/model/specs/generated/enums.py,sha256=_7eYhDClgRPrtt06o9N11enoKIIEUaHTBu9QGW3CABw,57079
61
+ openepd/model/specs/generated/finishes.py,sha256=xGjhNfpecOT7H4zElK34VSJuy8mfJ8gFF85PurKatao,22337
62
+ openepd/model/specs/generated/fire_and_smoke_protection.py,sha256=sbyEIMHB8zkIREqvUW6SSYZO9Tlx_zEoJrHWhqIjboI,2801
63
+ openepd/model/specs/generated/furnishings.py,sha256=NkS59ulTVqzSWFveM4Qd0Wv6bh0E-sx45fLrTH3Ixs4,3076
64
+ openepd/model/specs/generated/grouting.py,sha256=JAdrgzQObw_6nBeM6KHoTShXXBhG_38qDi6vOHvxXWM,1023
65
+ openepd/model/specs/generated/manufacturing_inputs.py,sha256=zlGyBUyGIW7Ruyt5XkPgu_q9yGaTFJQ4sjkdGQ-LucA,4599
66
+ openepd/model/specs/generated/masonry.py,sha256=VUd5Noeqtv8NWQfTqnM_8O0GZroib_pMipll2-pYQr8,3177
67
+ openepd/model/specs/generated/material_handling.py,sha256=qiyo_nH4nXmvTZxebqhOMXytCtpcQolHf3OLs1LBOx8,1225
68
+ openepd/model/specs/generated/mechanical.py,sha256=fELaoqPbNhgOQ_6oB8NIRfgz7Nff_nB6rqb0um1MGKY,11561
69
+ openepd/model/specs/generated/mechanical_insulation.py,sha256=CAtiQCPZUnRnfnKS8upqxQGuWoizCk4Hq8hgxg_0ZoA,1900
70
+ openepd/model/specs/generated/network_infrastructure.py,sha256=rejSwn6i0Ns4K2tFbv212wroM-zT4B2vTeIr3g8MVeg,8644
71
+ openepd/model/specs/generated/openings.py,sha256=n-SSgG-xHNwHGnKK5JN1PxLkxspTtSf8rgizXf3KtJs,17100
72
+ openepd/model/specs/generated/other_electrical_equipment.py,sha256=06HI_DEoHlywStzhj8rQtkfnXyWc-4Q4O3iE2rv4h2I,1057
73
+ openepd/model/specs/generated/other_materials.py,sha256=DCVKE_C0aVdotwayPuMATTlEmDjfTUm3-cQ8gzdxGMw,3453
74
+ openepd/model/specs/generated/plumbing.py,sha256=MOtI9aRGHtW64hui2x9ayHgkhtXtem0Aa6GTHJMpHw8,5439
75
+ openepd/model/specs/generated/precast_concrete.py,sha256=0aMCCXnCCgt7GGvjAppFAe-Hidjn-rokpvhOL1YgK0A,2690
76
+ openepd/model/specs/generated/sheathing.py,sha256=pV_j6R8mZ7Kyr8WYxP6UzsP3qSAqwxbVfe9V7jjSYb0,3516
77
+ openepd/model/specs/generated/steel.py,sha256=F3YzUb7jxUISn04Ye1NtMKORiYaqFfqfixTMfQWUJQY,8102
78
+ openepd/model/specs/generated/thermal_moisture_protection.py,sha256=3rqYO7_ljDMF_SLy0SsMjuiciOyL2qgVCyYz3b9ouTM,7963
79
+ openepd/model/specs/generated/utility_piping.py,sha256=qUJEFUWMav-TTB4UcJhRW2E_xftBwr0NwL_oTZmLuLQ,2768
80
+ openepd/model/specs/generated/wood.py,sha256=w_z9b2bIBjNyLEsn8MvFxVo0sVSuK75Mmuh9fQbOqgo,6199
81
+ openepd/model/specs/generated/wood_joists.py,sha256=UFakZ93LJqr-gSUz8hTyjx7BwHBq0BzWjpSKZ1B5TgQ,1880
82
+ openepd/model/specs/glass.py,sha256=JNIYlG7ybWTBPWBHq6kRGT4ibkkWGkDbb61zLPhKOPk,13664
83
+ openepd/model/specs/steel.py,sha256=6yRH_HK36kqn5XfAuF0_Q6TQtmeAc163qGIeStFGCM0,6367
84
+ openepd/model/specs/wood.py,sha256=DtviU3TrcWW74of8si2PCmaHxrdKWO1M2rSCBo_n6v8,5144
85
+ openepd/model/standard.py,sha256=8F70DCagplBe7IvkGJOUmt7td-uh_8zzdpvuVpjk0GY,1535
86
+ openepd/model/validation/__init__.py,sha256=rqQJWF5jpYAgRbbAycUfWMGsr5kGtfjmwzsTeqbElJw,837
87
+ openepd/model/validation/common.py,sha256=TPxIUtTNqNLiDsvuSE_dVREtNBe6XsagVMH4u1MYfpA,2652
88
+ openepd/model/validation/numbers.py,sha256=4gkMS35zKnGyfdFyLTgHncNmKpg8-WOYX9qaUr5scE4,1105
89
+ openepd/model/validation/quantity.py,sha256=GIPPtzOVwMYgKpx1XbDmoLQERlcoQ-VSK6k_EyMNQoQ,5287
90
+ openepd/model/versioning.py,sha256=1gqeeAhc2lVonq9ErOD3Ws7XZ0CgZnmlFpKHKrc9IwI,4690
91
+ openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
+ openepd-3.1.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
93
+ openepd-3.1.0.dist-info/METADATA,sha256=Dt47lv5UUQqXIW6C9fmatu1y0m8qsnDqMe5LekwXqYM,7762
94
+ openepd-3.1.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
95
+ openepd-3.1.0.dist-info/RECORD,,
@@ -1,22 +0,0 @@
1
- openepd/__init__.py,sha256=7_QNx3x9RCC7Lj9fHDD3nzgq6wV4Fmou7OJNWkCPnEw,837
2
- openepd/__version__.py,sha256=o25JgAoI-IMF0vY6N8fBeWWG4eM6srG-yDZ5JQMBUkI,855
3
- openepd/bundle/__init__.py,sha256=7_QNx3x9RCC7Lj9fHDD3nzgq6wV4Fmou7OJNWkCPnEw,837
4
- openepd/bundle/base.py,sha256=5fhPzpQug8GTroJ8N2BaL15Uo0hf05E8hmJRahlf4rY,7086
5
- openepd/bundle/model.py,sha256=cBKmeGmoPlp_RRmvTYHz9JNiIacz87846NkM4qXzWaM,2668
6
- openepd/bundle/reader.py,sha256=OsB7HmGzKwl4s1rBUeW6E2LTLN2E3-H81gt-o4LE0UM,6935
7
- openepd/bundle/writer.py,sha256=m-XTDqvy2aHCxSUtrKjDYgZPTl9jUlHzdCE-nwT0mqs,8366
8
- openepd/model/__init__.py,sha256=7_QNx3x9RCC7Lj9fHDD3nzgq6wV4Fmou7OJNWkCPnEw,837
9
- openepd/model/base.py,sha256=tpExVmKlvli1wS33SNXJKf-Dv3ue_B7pJUB4W5kLjn8,5361
10
- openepd/model/common.py,sha256=443ZHYUiaupipu4_fPsTEUtGg9moKDPFJimkQZNXZJE,5617
11
- openepd/model/epd.py,sha256=jpmqRvANedeSNnfEEzzURHAnNiQGTo_YHb6B6B4BBY4,13737
12
- openepd/model/lcia.py,sha256=OwmuDmeU2h8ScqlXV1t1scFcMJ840FqR3tXidx0bn3Q,16731
13
- openepd/model/org.py,sha256=yQd6H6SY8kwUj5CN7RTZvHBQmGvL9YFPMjga_AlaUCE,3816
14
- openepd/model/pcr.py,sha256=Z3Uqs5qa2YTSb01-iB1K5DpQSrCpOeSxEq9Zu7raxuk,3372
15
- openepd/model/specs/__init__.py,sha256=JmbvfzwO0QmNcrxGqYE_KjvYHBmc2bnDm7cyZsaMG78,1137
16
- openepd/model/specs/concrete.py,sha256=oIztCmkBwHa5fvPSlDwrYfAUpFaCG58FOg0FmFFykb4,3354
17
- openepd/model/standard.py,sha256=Nv_H3Lhu79y4waWzzKpwODCPPGrlWwRIl6eZBMSc9Qg,1519
18
- openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- openepd-2.0.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
20
- openepd-2.0.0.dist-info/METADATA,sha256=H8k3xipw3m62vkB1ynhV1LrgazELL9gvz199pWquQp0,6691
21
- openepd-2.0.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
22
- openepd-2.0.0.dist-info/RECORD,,