Language : Python
Generator Version : 2.107.0
Hi,
I’m writing a Python function that deals with the TimeSeries property of an Ontology object. I’ve confirmed that the generated OSDK properly maps a TimeSeries class to the object property, and I followed the documentation to calculate the mean value.
However, I ran into the following exception:
Example function:
@function
def timeseries_example_function(machinePart: Part, start: datetime, end: datetime) -> float:
df = machinePart.timeseries_property.to_pandas(start=start, end=end) # -> causes exception
return df["value"].mean()
Logs:
...
File "/scratch/standalone/ /code-assist/contents/python-functions/python/python_functions/my_function.py", line 16, in timeseires_example_function
df = machinePart.timeseries_property.to_pandas(start=start, end=end)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/scratch/standalone/ /code-assist/contents/python-functions/build/conda/test-env/lib/python3.12/site-packages/foundry_sdk_runtime/timeseries/timeseries.py", line 140, in to_pandas
stream_reader = query.arrow_stream()
^^^^^^^^^^^^^^^^^^^^
File "/scratch/standalone/ /code-assist/contents/python-functions/build/conda/test-env/lib/python3.12/site-packages/foundry_sdk_runtime/timeseries/timeseries_query.py", line 42, in arrow_stream
stream = self._ontologies_client.TimeSeriesPropertyV2.stream_points(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/scratch/standalone/ /code-assist/contents/python-functions/build/conda/test-env/lib/python3.12/site-packages/foundry_sdk/_core/utils.py", line 96, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/scratch/standalone/ /code-assist/contents/python-functions/build/conda/test-env/lib/python3.12/site-packages/pydantic/_internal/_validate_call.py", line 39, in wrapper_function
return wrapper(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/scratch/standalone/ /code-assist/contents/python-functions/build/conda/test-env/lib/python3.12/site-packages/pydantic/_internal/_validate_call.py", line 136, in __call__
res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValidationError: 1 validation error for TimeSeriesPropertyV2Client.stream_points
range
Unable to extract tag using discriminator 'type' [type=union_tag_not_found, input_value={'range': {'type': 'absol...'}}, input_type=dict]
My Investigation & Suspected Cause
I’ve traced the call stack and analyzed the SDK code. The issue seems to be a mismatch between the object created by TimeseriesQuery and the object expected by the TimeSeriesPropertyV2.stream_points API.
1. Call chain
The .to_pandas() method calls TimeseriesQuery.arrow_stream(), which in leads to calling the TimeSeriesPropertyV2.stream_points API endpoint.
foundry_sdk_runtime/timeseries/timeseries_query.py :
# The arrow_stream method in TimeseriesQuery calls the low-level API
stream = self._ontologies_client.TimeSeriesPropertyV2.stream_points(
ontology=self._ontology_rid,
object_type=self._object_type,
primary_key=str(self._object_primary_key),
property=self._property_name,
format="ARROW",
range=self._time_range, # <--- This is the argument causing the issue
)
2. API’s expectation
The stream_points method uses a Pydantic model that expects a TimeRange object. This model is a discriminated union identified by the type field.
TimeRange = typing_extensions.Annotated[
typing.Union[AbsoluteTimeRange, RelativeTimeRange], pydantic.Field(discriminator="type")
]
# The API signature expecting the model
def stream_points(
self,
...
range: typing.Optional[ontologies_models.TimeRange] = None,
...
) -> bytes:
pass
Therefore, the expected JSON structure for the range argument would be like below.
{
"type": "absolute",
"startTime": "2025-08-30T15:00:00Z",
"endTime": "2025-08-30T16:00:00Z"
}
3. TimeseriesQuery
The TimeseriesQuery class incorrectly wraps the TimeRange object inside another dictionary with a "range" key.
# foundry_sdk_runtime/timeseries/types.py :
class RelativeTimeRange(AliasedBaseModel):
type: Literal["relative"] = "relative"
startTime: Optional[RelativeTime]
endTime: Optional[RelativeTime]
class AbsoluteTimeRange(AliasedBaseModel):
type: Literal["absolute"] = "absolute"
startTime: Optional[datetime]
endTime: Optional[datetime]
class TimeRange(AliasedBaseModel):
range: Union[AbsoluteTimeRange, RelativeTimeRange]
# foundry_sdk_runtime/timeseries/timeseries_query.py :
class TimeseriesQuery(Generic[T]):
def __init__(
self,
# ...
time_range: Optional[TimeRange] = None,
):
# ...
self._time_range = json.loads(time_range.model_dump_json()) if time_range is not None else {}
As a result, the actual object being passed to the range parameter would be :
{
"range": {
"type": "absolute",
"startTime": "2025-08-30T15:00:00Z",
"endTime": "2025-08-30T16:00:00Z"
}
}
I believe this causes the fail of Pydantic validation, which is looking for the type field at the top level.
Also, although I can’t debug the SDK directly, I could find the relevant exception log.
related line)
Unable to extract tag using discriminator 'type' [type=union_tag_not_found, input_value={'range': {'type': 'absol...8-28T16:50:31.726000Z'}}, input_type=dict]
Since I cannot debug or modify the SDK directly, my current workaround is using Typescript function.
Has anyone else encountered this issue? Is there a Python-side workaround to properly unwrap or pass the range so .to_pandas() works without validation errors?
Thanks in advance!