openepd 5.2.0__py3-none-any.whl → 5.3.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 CHANGED
@@ -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 = "5.2.0"
16
+ VERSION = "5.3.0"
@@ -21,7 +21,7 @@ from openepd.api.base_sync_client import BaseApiMethodGroup
21
21
  from openepd.api.common import StreamingListResponse, paging_meta_from_v1_api
22
22
  from openepd.api.dto.common import BaseMeta, OpenEpdApiResponse
23
23
  from openepd.api.dto.meta import PagingMetaMixin
24
- from openepd.api.utils import encode_path_param
24
+ from openepd.api.utils import encode_path_param, remove_none_id_fields
25
25
  from openepd.model.generic_estimate import (
26
26
  GenericEstimate,
27
27
  GenericEstimatePreview,
@@ -57,26 +57,33 @@ class GenericEstimateApi(BaseApiMethodGroup):
57
57
 
58
58
  @overload
59
59
  def post_with_refs(
60
- self, ge: GenericEstimateWithDeps, with_response: Literal[True]
60
+ self, ge: GenericEstimateWithDeps, with_response: Literal[True], exclude_defaults: bool = True
61
61
  ) -> tuple[GenericEstimate, Response]: ...
62
62
 
63
63
  @overload
64
- def post_with_refs(self, ge: GenericEstimateWithDeps, with_response: Literal[False] = False) -> GenericEstimate: ...
64
+ def post_with_refs(
65
+ self, ge: GenericEstimateWithDeps, with_response: Literal[False] = False, exclude_defaults: bool = True
66
+ ) -> GenericEstimate: ...
65
67
 
66
68
  def post_with_refs(
67
- self, ge: GenericEstimateWithDeps, with_response: bool = False
69
+ self, ge: GenericEstimateWithDeps, with_response: bool = False, exclude_defaults: bool = True
68
70
  ) -> GenericEstimate | tuple[GenericEstimate, Response]:
69
71
  """
70
72
  Post an GenericEstimate with references.
71
73
 
72
74
  :param ge: GenericEstimate
73
75
  :param with_response: return the response object togather with the GenericEstimate
76
+ :param exclude_defaults: If True, fields with default values are excluded from the payload
74
77
  :return: GenericEstimate alone, or GenericEstimate with HTTP Response object depending on parameter
75
78
  """
79
+ data = ge.to_serializable(exclude_unset=True, exclude_defaults=exclude_defaults, by_alias=True)
80
+ if exclude_defaults is False:
81
+ # Remove 'id' fields with None values, as 'id' cannot be None
82
+ data = remove_none_id_fields(data)
76
83
  response = self._client.do_request(
77
84
  "patch",
78
85
  "/generic_estimates/post_with_refs",
79
- json=ge.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
86
+ json=data,
80
87
  )
81
88
  content = response.json()
82
89
  if with_response:
@@ -20,7 +20,7 @@ from requests import Response
20
20
  from openepd.api.base_sync_client import BaseApiMethodGroup
21
21
  from openepd.api.common import StreamingListResponse
22
22
  from openepd.api.epd.dto import EpdSearchResponse, EpdStatisticsResponse, StatisticsDto
23
- from openepd.api.utils import encode_path_param
23
+ from openepd.api.utils import encode_path_param, remove_none_id_fields
24
24
  from openepd.model.epd import Epd
25
25
 
26
26
 
@@ -106,23 +106,32 @@ class EpdApi(BaseApiMethodGroup):
106
106
  return self.get_statistics_raw(omf).payload
107
107
 
108
108
  @overload
109
- def post_with_refs(self, epd: Epd, with_response: Literal[True]) -> tuple[Epd, Response]: ...
109
+ def post_with_refs(
110
+ self, epd: Epd, with_response: Literal[True], exclude_defaults: bool = True
111
+ ) -> tuple[Epd, Response]: ...
110
112
 
111
113
  @overload
112
- def post_with_refs(self, epd: Epd, with_response: Literal[False] = False) -> Epd: ...
114
+ def post_with_refs(self, epd: Epd, with_response: Literal[False] = False, exclude_defaults: bool = True) -> Epd: ...
113
115
 
114
- def post_with_refs(self, epd: Epd, with_response: bool = False) -> Epd | tuple[Epd, Response]:
116
+ def post_with_refs(
117
+ self, epd: Epd, with_response: bool = False, exclude_defaults: bool = True
118
+ ) -> Epd | tuple[Epd, Response]:
115
119
  """
116
120
  Post an EPD with references.
117
121
 
118
122
  :param epd: EPD
119
123
  :param with_response: return the response object togather with the EPD
124
+ :param exclude_defaults: If True, fields with default values are excluded from the payload
120
125
  :return: EPD or EPD with HTTP Response object depending on parameter
121
126
  """
127
+ epd_data = epd.to_serializable(exclude_unset=True, exclude_defaults=exclude_defaults, by_alias=True)
128
+ if exclude_defaults is False:
129
+ # Remove 'id' fields with None values, as 'id' cannot be None
130
+ epd_data = remove_none_id_fields(epd_data)
122
131
  response = self._client.do_request(
123
132
  "patch",
124
133
  "/epds/post-with-refs",
125
- json=epd.to_serializable(exclude_unset=True, exclude_defaults=True, by_alias=True),
134
+ json=epd_data,
126
135
  )
127
136
  content = response.json()
128
137
  if with_response:
openepd/api/utils.py CHANGED
@@ -26,3 +26,43 @@ def encode_path_param(value: str) -> str:
26
26
  :return: encoded value
27
27
  """
28
28
  return quote(value, safe="")
29
+
30
+
31
+ def remove_none_id_fields(d: dict) -> dict:
32
+ """
33
+ Remove any key 'id' with a None value from the dictionary, including nested dicts.
34
+
35
+ :param d: the dict which may contain 'id' keys with None values.
36
+ :return: a new dict with 'id' keys that have None values removed.
37
+
38
+ :note:
39
+ - This function does not modify the original dictionary (no side effects).
40
+ - It returns a new dictionary with the necessary modifications applied.
41
+
42
+ :example:
43
+ >>> data = {
44
+ ... "id": None,
45
+ ... "name": "item1",
46
+ ... "details": {
47
+ ... "id": None,
48
+ ... "category": "tools",
49
+ ... "nested": {
50
+ ... "id": None,
51
+ ... "value": 42
52
+ ... }
53
+ ... }
54
+ ... }
55
+ >>> remove_none_id_fields(data)
56
+ {'name': 'item1', 'details': {'category': 'tools', 'nested': {'value': 42}}}
57
+ """
58
+ if not isinstance(d, dict):
59
+ return d
60
+
61
+ cleaned_dict = {}
62
+ for k, v in d.items():
63
+ if isinstance(v, dict):
64
+ v = remove_none_id_fields(v)
65
+ if not (k == "id" and v is None):
66
+ cleaned_dict[k] = v
67
+
68
+ return cleaned_dict
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openepd
3
- Version: 5.2.0
3
+ Version: 5.3.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
@@ -1,8 +1,8 @@
1
1
  openepd/__init__.py,sha256=Shkfh0Kun0YRhmRDw7LkUj2eQL3X-HnP55u2THOEALw,794
2
- openepd/__version__.py,sha256=kbk6lMDGVEMCkU1Pk1p1wyGQXEfbVXyh26UjUL-A4YI,638
2
+ openepd/__version__.py,sha256=eEVqmdbsGDJ4vyFA7va4C2zZ4rWy5ZZzKevZvLZTPtQ,638
3
3
  openepd/api/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
4
4
  openepd/api/average_dataset/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
5
- openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=DM7i8gugUIEAutEsakEUxFjwgtKmcytkjvNAvfhVYUs,7690
5
+ openepd/api/average_dataset/generic_estimate_sync_api.py,sha256=5dWtdyzs9WGO5-liQGZd0o5q0tSjoJrx1RCtjSnRrrk,8110
6
6
  openepd/api/average_dataset/industry_epd_sync_api.py,sha256=xoicuZdclf4BTBa2ndG1K2Aog-iZd7_jOqdDPZSCLq4,6286
7
7
  openepd/api/base_sync_client.py,sha256=IX-q6JdWLMqYHC-hKLXUFRPs-DZZ9Co0NRZ5pSAipAs,20992
8
8
  openepd/api/category/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
@@ -17,13 +17,13 @@ openepd/api/dto/mf.py,sha256=tjsxF6yJhnOrcOepNVHBn18pF-kXkBoUYfTQwOTaY2g,1994
17
17
  openepd/api/dto/params.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
18
18
  openepd/api/epd/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
19
19
  openepd/api/epd/dto.py,sha256=NZ76vfUkCEkwDibQd2QCEQP5DZms_NFc9tjoP-mcw3o,4874
20
- openepd/api/epd/sync_api.py,sha256=5wuPiM_zVciVtTvsGaaRdf7T6q2CUp7QMZCW0DAjQng,7072
20
+ openepd/api/epd/sync_api.py,sha256=EY9KVz8yDgmjgLzWWh2B3VobNswd9fZmfDFkiJTxog0,7522
21
21
  openepd/api/errors.py,sha256=Iipd0QW2tbhUu_UjUbmiFWgmrPVgOFHc3uxZN-SX-g4,2868
22
22
  openepd/api/pcr/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
23
23
  openepd/api/pcr/sync_api.py,sha256=Riu77h8uLJngKpITOiXYmO7mzjAHpYskUJ6ynyfNG78,1557
24
24
  openepd/api/sync_client.py,sha256=IurnhZrkBQoQIbbfon6TPuhjGpAV_CSTJNeXjIiN0QI,3105
25
25
  openepd/api/test/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
26
- openepd/api/utils.py,sha256=FSY2W8zTXGTvJAJACMi4nibpo-9m1HXkTCH8kdAYlzQ,875
26
+ openepd/api/utils.py,sha256=9kdWbJ-m0IqsrkPQpGkILIQlR1WPd9rRlko-ymj9gtI,2092
27
27
  openepd/bundle/__init__.py,sha256=UGmZGEyMnASrYwEBPHuXmVzHiuCUskUsJEPoHTIo-lg,620
28
28
  openepd/bundle/base.py,sha256=mOt3h3MuQyc1yunp9u6_CVYDtSdWQHZcx8cNfbNkqoY,6869
29
29
  openepd/bundle/model.py,sha256=yICEHl7ZWDXHGx4rhFomCwa-ganjUtykyj_fpWw_6OI,2446
@@ -133,7 +133,7 @@ openepd/model/validation/quantity.py,sha256=8LbSn-Gfo6r1j6AKDjzPnt_9dwyXMFmN5Uao
133
133
  openepd/model/versioning.py,sha256=R_zm6rCrgF3vlJQYbpyWhirdS_Oek16cv_mvZmpuE8I,4473
134
134
  openepd/patch_pydantic.py,sha256=xrkzblatmU9HBzukWkp1cPq9ZSuohoz1p0pQqVKSlKs,4122
135
135
  openepd/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
136
- openepd-5.2.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
137
- openepd-5.2.0.dist-info/METADATA,sha256=Ty91Z75VePUQGEPSLaD7hJROLHkCJ_6u2ueFFZ6IcC8,8996
138
- openepd-5.2.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
139
- openepd-5.2.0.dist-info/RECORD,,
136
+ openepd-5.3.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
137
+ openepd-5.3.0.dist-info/METADATA,sha256=twGr4uGcA4Rn0osNRGYw0IdWeC53yVy5NlbzhZNLZ6c,8996
138
+ openepd-5.3.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
139
+ openepd-5.3.0.dist-info/RECORD,,