From f29bb541f6af9740f6f562422b69714f7f1b8de7 Mon Sep 17 00:00:00 2001 From: Ilay Falach Date: Wed, 13 May 2026 14:19:53 +0300 Subject: [PATCH] Fix pandas 3.x / Python 3.12 compatibility in dataObjects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three breaking changes fixed: 1. Trial.__init__: replace broken pandas 3.x index merge with explicit join. merge(left_index=True, right_index=True) with mismatched index types no longer does positional matching in pandas 3.x — replaced with .join() after aligning both sides on the property key/name column. Also adds graceful fallback when label/description fields are absent. 2. _parseProperty_datetime_local: fix tz_localize on tz-aware Timestamps. pandas 3.x parses ISO strings ending with 'Z' as UTC tz-aware objects. Calling tz_localize() on an already-aware Timestamp raises TypeError. Fixed: check tzinfo first; use tz_convert() if already aware. Also replaces legacy "israel" timezone alias (not recognised by Python 3.12 zoneinfo) with the canonical "Asia/Jerusalem". 3. Trial.properties: remove incorrect re-parse of raw metadata. The property was re-reading self._metadata['properties'] using key/value field names that belong to entity attributes, not trial properties. __init__ already stores the correctly parsed result in self._properties; the property now simply returns that. Co-Authored-By: Claude Sonnet 4.6 --- argos/experimentSetup/dataObjects.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/argos/experimentSetup/dataObjects.py b/argos/experimentSetup/dataObjects.py index 6230afc..7e7acfe 100644 --- a/argos/experimentSetup/dataObjects.py +++ b/argos/experimentSetup/dataObjects.py @@ -902,13 +902,7 @@ def properties(self): A dictionary mapping property labels to their parsed values. """ - propDict = {} - propList = self._metadata['attributes'] if 'attributes' in self._metadata else self._metadata['properties'] - - for prop in propList: - propDict[prop['name']] = prop['value'] - - return propDict + return self._properties @property def trialSet(self): @@ -956,8 +950,18 @@ def __init__(self, trialSet: TrialSet, metadata: dict): if len(metadata.get('properties', [])): propertiesPandas = pandas.DataFrame(metadata['properties']).set_index('key') - properties = propertiesPandas.merge(trialSet.propertiesTable, left_index=True, right_index=True)[ - ['val', 'type', 'label', 'description']] + # pandas 3.x: merge on index requires matching index types/values. + # Build the attribute-type definitions indexed by key/name so the + # join aligns on property names rather than integer positions. + pts = pandas.DataFrame(trialSet.properties) + key_col = 'key' if 'key' in pts.columns else 'name' + pts = pts.set_index(key_col) + for col in ('label', 'description'): + if col not in pts.columns: + pts[col] = '' + properties = propertiesPandas[['val']].join( + pts[['type', 'label', 'description']], how='inner' + ) getParser = lambda x: getattr(self, f"_parseProperty_{x.replace('-', '_')}") # this wont work well for location property in the trial because it has 2 fields. @@ -1172,7 +1176,11 @@ def _parseProperty_datetime_local(self, property, propertyMetadata): if localdata is None: data = [None] else: - data = [localdata.tz_localize("israel")] + # pandas 3.x parses Z-suffix as tz-aware UTC; convert rather than localize + if localdata.tzinfo is not None: + data = [localdata.tz_convert("Asia/Jerusalem")] + else: + data = [localdata.tz_localize("Asia/Jerusalem")] columns = [propertyLabel] return columns, data