@@ -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