Skip to content

Commit e062783

Browse files
committed
merge with optionset change
1 parent 6e8f0bb commit e062783

1 file changed

Lines changed: 14 additions & 15 deletions

File tree

src/dataverse_sdk/odata.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,19 @@ def _create(self, logical_name: str, data: Union[Dict[str, Any], List[Dict[str,
9292
"""
9393
entity_set = self._entity_set_from_logical(logical_name)
9494
if isinstance(data, dict):
95-
return self._create_single(entity_set, data)
95+
return self._create_single(entity_set, logical_name, data)
9696
if isinstance(data, list):
9797
return self._create_multiple(entity_set, logical_name, data)
9898
raise TypeError("data must be dict or list[dict]")
9999

100100
# --- Internal helpers ---
101-
def _create_single(self, entity_set: str, record: Dict[str, Any]) -> str:
101+
def _create_single(self, entity_set: str, logical_name: str, record: Dict[str, Any]) -> str:
102102
"""Create a single record and return its GUID.
103103
104104
Relies on OData-EntityId (canonical) or Location header. No response body parsing is performed.
105105
Raises RuntimeError if neither header contains a GUID.
106106
"""
107-
record = self._convert_labels_to_ints(entity_set, record)
107+
record = self._convert_labels_to_ints(logical_name, record)
108108
url = f"{self.api}/{entity_set}"
109109
headers = self._headers().copy()
110110
r = self._request("post", url, headers=headers, json=record)
@@ -131,7 +131,7 @@ def _create_multiple(self, entity_set: str, logical_name: str, records: List[Dic
131131
need_logical = any("@odata.type" not in r for r in records)
132132
enriched: List[Dict[str, Any]] = []
133133
for r in records:
134-
r = self._convert_labels_to_ints(entity_set, r)
134+
r = self._convert_labels_to_ints(logical_name, r)
135135
if "@odata.type" in r or not need_logical:
136136
enriched.append(r)
137137
else:
@@ -258,7 +258,7 @@ def _update(self, logical_name: str, key: str, data: Dict[str, Any]) -> None:
258258
-------
259259
None
260260
"""
261-
data = self._convert_labels_to_ints(entity_set, data)
261+
data = self._convert_labels_to_ints(logical_name, data)
262262
entity_set = self._entity_set_from_logical(logical_name)
263263
url = f"{self.api}/{entity_set}{self._format_key(key)}"
264264
headers = self._headers().copy()
@@ -303,7 +303,7 @@ def _update_multiple(self, entity_set: str, logical_name: str, records: List[Dic
303303
need_logical = any("@odata.type" not in r for r in records)
304304
enriched: List[Dict[str, Any]] = []
305305
for r in records:
306-
r = self._convert_labels_to_ints(entity_set, r)
306+
r = self._convert_labels_to_ints(logical_name, r)
307307
if "@odata.type" in r or not need_logical:
308308
enriched.append(r)
309309
else:
@@ -740,7 +740,7 @@ def _normalize_picklist_label(self, label: str) -> str:
740740
norm = re.sub(r"\s+", " ", norm).strip().lower()
741741
return norm
742742

743-
def _optionset_map(self, entity_set: str, attr_logical: str) -> Optional[Dict[str, int]]:
743+
def _optionset_map(self, logical_name: str, attr_logical: str) -> Optional[Dict[str, int]]:
744744
"""Build or return cached mapping of normalized label -> value for a picklist attribute.
745745
746746
Returns empty dict if attribute is not a picklist or has no options. Returns None only
@@ -750,17 +750,16 @@ def _optionset_map(self, entity_set: str, attr_logical: str) -> Optional[Dict[st
750750
-----
751751
- This method calls the Web API twice per attribute so it could have perf impact when there are lots of columns on the entity.
752752
"""
753-
if not entity_set or not attr_logical:
753+
if not logical_name or not attr_logical:
754754
return None
755-
logical = self._logical_from_entity_set(entity_set)
756-
cache_key = (logical, attr_logical.lower())
755+
cache_key = (logical_name, attr_logical.lower())
757756
now = time.time()
758757
entry = self._picklist_label_cache.get(cache_key)
759758
if isinstance(entry, dict) and 'map' in entry and (now - entry.get('ts', 0)) < self._picklist_cache_ttl_seconds:
760759
return entry['map']
761760

762761
attr_esc = self._escape_odata_quotes(attr_logical)
763-
logical_esc = self._escape_odata_quotes(logical)
762+
logical_esc = self._escape_odata_quotes(logical_name)
764763

765764
# Step 1: lightweight fetch (no expand) to determine attribute type
766765
url_type = (
@@ -779,7 +778,7 @@ def _optionset_map(self, entity_set: str, attr_logical: str) -> Optional[Dict[st
779778
if r_type.status_code == 404:
780779
# After retries we still cannot find the attribute definition – treat as fatal so caller sees a clear error.
781780
raise RuntimeError(
782-
f"Picklist attribute metadata not found after retries: entity='{logical}' attribute='{attr_logical}' (404)"
781+
f"Picklist attribute metadata not found after retries: entity='{logical_name}' attribute='{attr_logical}' (404)"
783782
)
784783
r_type.raise_for_status()
785784

@@ -807,7 +806,7 @@ def _optionset_map(self, entity_set: str, attr_logical: str) -> Optional[Dict[st
807806
if attempt < 2:
808807
time.sleep(0.4 * (2 ** attempt)) # 0.4s, 0.8s
809808
if r_opts.status_code == 404:
810-
raise RuntimeError(f"Picklist OptionSet metadata not found after retries: entity='{logical}' attribute='{attr_logical}' (404)")
809+
raise RuntimeError(f"Picklist OptionSet metadata not found after retries: entity='{logical_name}' attribute='{attr_logical}' (404)")
811810
r_opts.raise_for_status()
812811

813812
attr_full = {}
@@ -842,7 +841,7 @@ def _optionset_map(self, entity_set: str, attr_logical: str) -> Optional[Dict[st
842841
self._picklist_label_cache[cache_key] = {'map': {}, 'ts': now}
843842
return {}
844843

845-
def _convert_labels_to_ints(self, entity_set: str, record: Dict[str, Any]) -> Dict[str, Any]:
844+
def _convert_labels_to_ints(self, logical_name: str, record: Dict[str, Any]) -> Dict[str, Any]:
846845
"""Return a copy of record with any labels converted to option ints.
847846
848847
Heuristic: For each string value, attempt to resolve against picklist metadata.
@@ -852,7 +851,7 @@ def _convert_labels_to_ints(self, entity_set: str, record: Dict[str, Any]) -> Di
852851
for k, v in list(out.items()):
853852
if not isinstance(v, str) or not v.strip():
854853
continue
855-
mapping = self._optionset_map(entity_set, k)
854+
mapping = self._optionset_map(logical_name, k)
856855
if not mapping:
857856
continue
858857
norm = self._normalize_picklist_label(v)

0 commit comments

Comments
 (0)