diff --git a/examples/windmill/__init__.py b/examples/windmill/__init__.py
deleted file mode 100644
index 428145e51..000000000
--- a/examples/windmill/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from windmill._api_client import WindmillClient
-
-__all__ = ["WindmillClient"]
diff --git a/examples/windmill/_api/__init__.py b/examples/windmill/_api/__init__.py
deleted file mode 100644
index 1ddb05147..000000000
--- a/examples/windmill/_api/__init__.py
+++ /dev/null
@@ -1,129 +0,0 @@
-from windmill._api.blade import BladeAPI
-from windmill._api.blade_query import BladeQueryAPI
-from windmill._api.blade_sensor_positions import BladeSensorPositionsAPI
-from windmill._api.gearbox import GearboxAPI
-from windmill._api.gearbox_displacement_x import GearboxDisplacementXAPI
-from windmill._api.gearbox_displacement_y import GearboxDisplacementYAPI
-from windmill._api.gearbox_displacement_z import GearboxDisplacementZAPI
-from windmill._api.gearbox_query import GearboxQueryAPI
-from windmill._api.generator import GeneratorAPI
-from windmill._api.generator_generator_speed_controller import GeneratorGeneratorSpeedControllerAPI
-from windmill._api.generator_generator_speed_controller_reference import GeneratorGeneratorSpeedControllerReferenceAPI
-from windmill._api.generator_query import GeneratorQueryAPI
-from windmill._api.high_speed_shaft import HighSpeedShaftAPI
-from windmill._api.high_speed_shaft_bending_moment_y import HighSpeedShaftBendingMomentYAPI
-from windmill._api.high_speed_shaft_bending_monent_x import HighSpeedShaftBendingMonentXAPI
-from windmill._api.high_speed_shaft_query import HighSpeedShaftQueryAPI
-from windmill._api.high_speed_shaft_torque import HighSpeedShaftTorqueAPI
-from windmill._api.main_shaft import MainShaftAPI
-from windmill._api.main_shaft_bending_x import MainShaftBendingXAPI
-from windmill._api.main_shaft_bending_y import MainShaftBendingYAPI
-from windmill._api.main_shaft_calculated_tilt_moment import MainShaftCalculatedTiltMomentAPI
-from windmill._api.main_shaft_calculated_yaw_moment import MainShaftCalculatedYawMomentAPI
-from windmill._api.main_shaft_query import MainShaftQueryAPI
-from windmill._api.main_shaft_torque import MainShaftTorqueAPI
-from windmill._api.metmast import MetmastAPI
-from windmill._api.metmast_query import MetmastQueryAPI
-from windmill._api.metmast_temperature import MetmastTemperatureAPI
-from windmill._api.metmast_tilt_angle import MetmastTiltAngleAPI
-from windmill._api.metmast_wind_speed import MetmastWindSpeedAPI
-from windmill._api.nacelle import NacelleAPI
-from windmill._api.nacelle_acc_from_back_side_x import NacelleAccFromBackSideXAPI
-from windmill._api.nacelle_acc_from_back_side_y import NacelleAccFromBackSideYAPI
-from windmill._api.nacelle_acc_from_back_side_z import NacelleAccFromBackSideZAPI
-from windmill._api.nacelle_query import NacelleQueryAPI
-from windmill._api.nacelle_yaw_direction import NacelleYawDirectionAPI
-from windmill._api.nacelle_yaw_error import NacelleYawErrorAPI
-from windmill._api.power_inverter import PowerInverterAPI
-from windmill._api.power_inverter_active_power_total import PowerInverterActivePowerTotalAPI
-from windmill._api.power_inverter_apparent_power_total import PowerInverterApparentPowerTotalAPI
-from windmill._api.power_inverter_query import PowerInverterQueryAPI
-from windmill._api.power_inverter_reactive_power_total import PowerInverterReactivePowerTotalAPI
-from windmill._api.rotor import RotorAPI
-from windmill._api.rotor_query import RotorQueryAPI
-from windmill._api.rotor_rotor_speed_controller import RotorRotorSpeedControllerAPI
-from windmill._api.rotor_rpm_low_speed_shaft import RotorRpmLowSpeedShaftAPI
-from windmill._api.sensor_position import SensorPositionAPI
-from windmill._api.sensor_position_edgewise_bend_mom_crosstalk_corrected import (
- SensorPositionEdgewiseBendMomCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_edgewise_bend_mom_offset import SensorPositionEdgewiseBendMomOffsetAPI
-from windmill._api.sensor_position_edgewise_bend_mom_offset_crosstalk_corrected import (
- SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_edgewisewise_bend_mom import SensorPositionEdgewisewiseBendMomAPI
-from windmill._api.sensor_position_flapwise_bend_mom import SensorPositionFlapwiseBendMomAPI
-from windmill._api.sensor_position_flapwise_bend_mom_crosstalk_corrected import (
- SensorPositionFlapwiseBendMomCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_flapwise_bend_mom_offset import SensorPositionFlapwiseBendMomOffsetAPI
-from windmill._api.sensor_position_flapwise_bend_mom_offset_crosstalk_corrected import (
- SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_query import SensorPositionQueryAPI
-from windmill._api.windmill import WindmillAPI
-from windmill._api.windmill_blades import WindmillBladesAPI
-from windmill._api.windmill_metmast import WindmillMetmastAPI
-from windmill._api.windmill_query import WindmillQueryAPI
-
-__all__ = [
- "BladeAPI",
- "BladeQueryAPI",
- "BladeSensorPositionsAPI",
- "GearboxAPI",
- "GearboxDisplacementXAPI",
- "GearboxDisplacementYAPI",
- "GearboxDisplacementZAPI",
- "GearboxQueryAPI",
- "GeneratorAPI",
- "GeneratorGeneratorSpeedControllerAPI",
- "GeneratorGeneratorSpeedControllerReferenceAPI",
- "GeneratorQueryAPI",
- "HighSpeedShaftAPI",
- "HighSpeedShaftBendingMomentYAPI",
- "HighSpeedShaftBendingMonentXAPI",
- "HighSpeedShaftQueryAPI",
- "HighSpeedShaftTorqueAPI",
- "MainShaftAPI",
- "MainShaftBendingXAPI",
- "MainShaftBendingYAPI",
- "MainShaftCalculatedTiltMomentAPI",
- "MainShaftCalculatedYawMomentAPI",
- "MainShaftQueryAPI",
- "MainShaftTorqueAPI",
- "MetmastAPI",
- "MetmastQueryAPI",
- "MetmastTemperatureAPI",
- "MetmastTiltAngleAPI",
- "MetmastWindSpeedAPI",
- "NacelleAPI",
- "NacelleAccFromBackSideXAPI",
- "NacelleAccFromBackSideYAPI",
- "NacelleAccFromBackSideZAPI",
- "NacelleQueryAPI",
- "NacelleYawDirectionAPI",
- "NacelleYawErrorAPI",
- "PowerInverterAPI",
- "PowerInverterActivePowerTotalAPI",
- "PowerInverterApparentPowerTotalAPI",
- "PowerInverterQueryAPI",
- "PowerInverterReactivePowerTotalAPI",
- "RotorAPI",
- "RotorQueryAPI",
- "RotorRotorSpeedControllerAPI",
- "RotorRpmLowSpeedShaftAPI",
- "SensorPositionAPI",
- "SensorPositionEdgewiseBendMomCrosstalkCorrectedAPI",
- "SensorPositionEdgewiseBendMomOffsetAPI",
- "SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedAPI",
- "SensorPositionEdgewisewiseBendMomAPI",
- "SensorPositionFlapwiseBendMomAPI",
- "SensorPositionFlapwiseBendMomCrosstalkCorrectedAPI",
- "SensorPositionFlapwiseBendMomOffsetAPI",
- "SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedAPI",
- "SensorPositionQueryAPI",
- "WindmillAPI",
- "WindmillBladesAPI",
- "WindmillMetmastAPI",
- "WindmillQueryAPI",
-]
diff --git a/examples/windmill/_api/_core.py b/examples/windmill/_api/_core.py
deleted file mode 100644
index ffae305f5..000000000
--- a/examples/windmill/_api/_core.py
+++ /dev/null
@@ -1,601 +0,0 @@
-from __future__ import annotations
-
-from abc import ABC
-from collections import defaultdict
-from collections.abc import Sequence
-from itertools import groupby
-from typing import (
- Generic,
- Literal,
- Any,
- Iterator,
- Protocol,
- SupportsIndex,
- TypeVar,
- overload,
- ClassVar,
-)
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import TimeSeriesList
-from cognite.client.data_classes.data_modeling.instances import InstanceSort, InstanceAggregationResultList
-
-from windmill import data_classes
-from windmill.data_classes._core import (
- DomainModel,
- DomainModelWrite,
- DEFAULT_INSTANCE_SPACE,
- PageInfo,
- GraphQLCore,
- GraphQLList,
- ResourcesWriteResult,
- T_DomainModel,
- T_DomainModelWrite,
- T_DomainModelWriteList,
- T_DomainModelList,
- T_DomainRelation,
- T_DomainRelationWrite,
- T_DomainRelationList,
- DataClassQueryBuilder,
- NodeQueryStep,
- EdgeQueryStep,
-)
-
-DEFAULT_LIMIT_READ = 25
-DEFAULT_QUERY_LIMIT = 3
-IN_FILTER_LIMIT = 5_000
-INSTANCE_QUERY_LIMIT = 1_000
-NODE_PROPERTIES = {"externalId", "space"}
-
-Aggregations = Literal["avg", "count", "max", "min", "sum"]
-
-_METRIC_AGGREGATIONS_BY_NAME = {
- "avg": dm.aggregations.Avg,
- "count": dm.aggregations.Count,
- "max": dm.aggregations.Max,
- "min": dm.aggregations.Min,
- "sum": dm.aggregations.Sum,
-}
-
-_T_co = TypeVar("_T_co", covariant=True)
-
-
-def _as_node_id(value: str | dm.NodeId | tuple[str, str], space: str) -> dm.NodeId:
- if isinstance(value, str):
- return dm.NodeId(space=space, external_id=value)
- if isinstance(value, dm.NodeId):
- return value
- if isinstance(value, tuple):
- return dm.NodeId(space=value[0], external_id=value[1])
- raise TypeError(f"Expected str, NodeId or tuple, got {type(value)}")
-
-
-# Source from https://github.com/python/typing/issues/256#issuecomment-1442633430
-# This works because str.__contains__ does not accept an object (either in typeshed or at runtime)
-class SequenceNotStr(Protocol[_T_co]):
- @overload
- def __getitem__(self, index: SupportsIndex, /) -> _T_co: ...
-
- @overload
- def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ...
-
- def __contains__(self, value: object, /) -> bool: ...
-
- def __len__(self) -> int: ...
-
- def __iter__(self) -> Iterator[_T_co]: ...
-
- def index(self, value: Any, /, start: int = 0, stop: int = ...) -> int: ...
-
- def count(self, value: Any, /) -> int: ...
-
- def __reversed__(self) -> Iterator[_T_co]: ...
-
-
-class NodeReadAPI(Generic[T_DomainModel, T_DomainModelList], ABC):
- _view_id: ClassVar[dm.ViewId]
- _properties_by_field: ClassVar[dict[str, str]]
- _direct_children_by_external_id: ClassVar[dict[str, type[DomainModel]]]
- _class_type: type[T_DomainModel]
- _class_list: type[T_DomainModelList]
-
- def __init__(self, client: CogniteClient):
- self._client = client
-
- def _delete(self, external_id: str | SequenceNotStr[str], space: str) -> dm.InstancesDeleteResult:
- if isinstance(external_id, str):
- return self._client.data_modeling.instances.delete(nodes=(space, external_id))
- else:
- return self._client.data_modeling.instances.delete(
- nodes=[(space, id) for id in external_id],
- )
-
- def _retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str,
- retrieve_edges: bool = False,
- edge_api_name_type_direction_view_id_penta: (
- list[tuple[EdgeAPI, str, dm.DirectRelationReference, Literal["outwards", "inwards"], dm.ViewId]] | None
- ) = None,
- as_child_class: SequenceNotStr[str] | None = None,
- ) -> T_DomainModel | T_DomainModelList | None:
- if isinstance(external_id, str | dm.NodeId) or (
- isinstance(external_id, tuple) and len(external_id) == 2 and all(isinstance(i, str) for i in external_id)
- ):
- node_ids = [_as_node_id(external_id, space)]
- is_multiple = False
- else:
- is_multiple = True
- node_ids = [_as_node_id(ext_id, space) for ext_id in external_id]
-
- items: list[DomainModel] = []
- if as_child_class:
- if not hasattr(self, "_direct_children_by_external_id"):
- raise ValueError(f"{type(self).__name__} does not have any direct children")
- for child_class_external_id in as_child_class:
- child_cls = self._direct_children_by_external_id.get(child_class_external_id)
- if child_cls is None:
- raise ValueError(f"Could not find child class with external_id {child_class_external_id}")
- instances = self._client.data_modeling.instances.retrieve(nodes=node_ids, sources=child_cls._view_id)
- items.extend([child_cls.from_instance(node) for node in instances.nodes])
- else:
- instances = self._client.data_modeling.instances.retrieve(nodes=node_ids, sources=self._view_id)
- items.extend([self._class_type.from_instance(node) for node in instances.nodes])
-
- nodes = self._class_list(items)
-
- if retrieve_edges and nodes:
- self._retrieve_and_set_edge_types(nodes, edge_api_name_type_direction_view_id_penta)
-
- if is_multiple:
- return nodes
- elif not nodes:
- return None
- else:
- return nodes[0]
-
- def _search(
- self,
- query: str,
- properties: str | SequenceNotStr[str] | None = None,
- filter_: dm.Filter | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- sort_by: str | list[str] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> T_DomainModelList:
- properties_input = self._to_input_properties(properties)
-
- sort_input = self._create_sort(sort_by, direction, sort)
- nodes = self._client.data_modeling.instances.search(
- view=self._view_id,
- query=query,
- instance_type="node",
- properties=properties_input,
- filter=filter_,
- limit=limit,
- sort=sort_input,
- )
- return self._class_list([self._class_type.from_instance(node) for node in nodes])
-
- def _to_input_properties(self, properties: str | SequenceNotStr[str] | None) -> list[str] | None:
- properties_input: list[str] | None = None
- if isinstance(properties, str):
- properties_input = [properties]
- elif isinstance(properties, Sequence):
- properties_input = list(properties)
- if properties_input:
- properties_input = [self._properties_by_field.get(prop, prop) for prop in properties_input]
- return properties_input
-
- def _aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: str | SequenceNotStr[str] | None = None,
- properties: str | SequenceNotStr[str] | None = None,
- query: str | None = None,
- search_properties: str | SequenceNotStr[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- if isinstance(group_by, str):
- group_by = [group_by]
-
- if group_by:
- group_by = [self._properties_by_field.get(prop, prop) for prop in group_by]
-
- search_properties_input = self._to_input_properties(search_properties)
-
- if isinstance(properties, str):
- properties = [properties]
-
- if properties:
- properties = [self._properties_by_field.get(prop, prop) for prop in properties]
-
- if isinstance(aggregate, (str, dm.aggregations.MetricAggregation)):
- aggregate = [aggregate]
-
- if properties is None and (invalid := [agg for agg in aggregate if isinstance(agg, str) and agg != "count"]):
- raise ValueError(f"Cannot aggregate on {invalid} without specifying properties")
-
- aggregates: list[dm.aggregations.MetricAggregation] = []
- for agg in aggregate:
- if isinstance(agg, dm.aggregations.MetricAggregation):
- aggregates.append(agg)
- elif isinstance(agg, str):
- if agg == "count" and properties is None:
- aggregates.append(dm.aggregations.Count("externalId"))
- elif properties is None:
- raise ValueError(f"Cannot aggregate on {agg} without specifying properties")
- else:
- for prop in properties:
- aggregates.append(_METRIC_AGGREGATIONS_BY_NAME[agg](prop))
- else:
- raise TypeError(f"Expected str or MetricAggregation, got {type(agg)}")
-
- return self._client.data_modeling.instances.aggregate(
- view=self._view_id,
- aggregates=aggregates,
- group_by=group_by,
- instance_type="node",
- query=query,
- properties=search_properties_input,
- filter=filter,
- limit=limit,
- )
-
- def _histogram(
- self,
- property: str,
- interval: float,
- query: str | None = None,
- search_properties: str | SequenceNotStr[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- property = self._properties_by_field.get(property, property)
-
- if isinstance(search_properties, str):
- search_properties = [search_properties]
- if search_properties:
- search_properties = [self._properties_by_field.get(prop, prop) for prop in search_properties]
-
- return self._client.data_modeling.instances.histogram(
- view=self._view_id,
- histograms=dm.aggregations.Histogram(property, interval),
- instance_type="node",
- query=query,
- properties=search_properties,
- filter=filter,
- limit=limit,
- )
-
- def _list(
- self,
- limit: int,
- filter: dm.Filter | None,
- retrieve_edges: bool = False,
- edge_api_name_type_direction_view_id_penta: (
- list[tuple[EdgeAPI, str, dm.DirectRelationReference, Literal["outwards", "inwards"], dm.ViewId]] | None
- ) = None,
- sort_by: str | list[str] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> T_DomainModelList:
- sort_input = self._create_sort(sort_by, direction, sort)
- nodes = self._client.data_modeling.instances.list(
- instance_type="node",
- sources=self._view_id,
- limit=limit,
- filter=filter,
- sort=sort_input,
- )
- node_list = self._class_list([self._class_type.from_instance(node) for node in nodes])
- if retrieve_edges and node_list:
- self._retrieve_and_set_edge_types(node_list, edge_api_name_type_direction_view_id_penta) # type: ignore[arg-type]
-
- return node_list
-
- def _create_sort(
- self,
- sort_by: str | list[str] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> list[InstanceSort] | None:
- sort_input: list[InstanceSort] | None = None
- if sort is None and isinstance(sort_by, str):
- sort_input = [self._create_sort_entry(sort_by, direction)]
- elif sort is None and isinstance(sort_by, list):
- sort_input = [self._create_sort_entry(sort_by_, direction) for sort_by_ in sort_by]
- elif sort is not None:
- sort_input = sort if isinstance(sort, list) else [sort]
- for sort_ in sort_input:
- if isinstance(sort_.property, Sequence) and len(sort_.property) == 1:
- sort_.property = self._create_property_reference(sort_.property[0])
- elif isinstance(sort_.property, str):
- sort_.property = self._create_property_reference(sort_.property)
- return sort_input
-
- def _create_sort_entry(self, sort_by: str, direction: Literal["ascending", "descending"]) -> InstanceSort:
- return InstanceSort(self._create_property_reference(sort_by), direction)
-
- def _create_property_reference(self, property_: str) -> list[str] | tuple[str, ...]:
- prop_name = self._properties_by_field.get(property_, property_)
- if prop_name in NODE_PROPERTIES:
- return ["node", prop_name]
- else:
- return self._view_id.as_property_ref(prop_name)
-
- def _retrieve_and_set_edge_types(
- self,
- nodes: T_DomainModelList, # type: ignore[misc]
- edge_api_name_type_direction_view_id_penta: (
- list[tuple[EdgeAPI, str, dm.DirectRelationReference, Literal["outwards", "inwards"], dm.ViewId]] | None
- ) = None,
- ):
- filter_: dm.Filter | None
- for edge_type, values in groupby(edge_api_name_type_direction_view_id_penta or [], lambda x: x[2].as_tuple()):
- edges: dict[dm.EdgeId, dm.Edge] = {}
- value_list = list(values)
- for edge_api, edge_name, edge_type, direction, view_id in value_list:
- is_type = dm.filters.Equals(
- ["edge", "type"],
- {"space": edge_type.space, "externalId": edge_type.external_id},
- )
- if len(ids := nodes.as_node_ids()) > IN_FILTER_LIMIT:
- filter_ = is_type
- else:
- is_nodes = dm.filters.In(
- ["edge", "startNode"] if direction == "outwards" else ["edge", "endNode"],
- values=[id_.dump(camel_case=True, include_instance_type=False) for id_ in ids],
- )
- filter_ = dm.filters.And(is_type, is_nodes)
- result = edge_api._list(limit=-1, filter_=filter_)
- edges.update({edge.as_id(): edge for edge in result})
- edge_list = list(edges.values())
- if len(value_list) == 1:
- _, edge_name, _, direction, _ = value_list[0]
- self._set_edges(nodes, edge_list, edge_name, direction)
- else:
- # This is an 'edge' case where we have view with multiple edges of the same type.
- edge_by_end_node: dict[tuple[str, str], list[dm.Edge]] = defaultdict(list)
- for edge in edge_list:
- node_id = edge.end_node.as_tuple() if direction == "outwards" else edge.start_node.as_tuple()
- edge_by_end_node[node_id].append(edge)
-
- for no, (edge_api, edge_name, _, direction, view_id) in enumerate(value_list):
- if not edge_by_end_node:
- break
- if no == len(value_list) - 1:
- # Last edge, use all remaining nodes
- attribute_edges = [e for e_list in edge_by_end_node.values() for e in e_list]
- else:
- existing = self._client.data_modeling.instances.retrieve(
- nodes=list(edge_by_end_node), sources=view_id
- )
- attribute_edges = []
- for node in existing.nodes:
- attribute_edge = edge_by_end_node.pop(node.as_id().as_tuple(), [])
- attribute_edges.extend(attribute_edge)
-
- self._set_edges(nodes, attribute_edges, edge_name, direction)
-
- @staticmethod
- def _set_edges(
- nodes: Sequence[DomainModel],
- edges: Sequence[dm.Edge],
- edge_name: str,
- direction: Literal["outwards", "inwards"],
- ):
- edges_by_node: dict[tuple, list] = defaultdict(list)
- for edge in edges:
- node_id = edge.start_node.as_tuple() if direction == "outwards" else edge.end_node.as_tuple()
- edges_by_node[node_id].append(edge)
-
- for node in nodes:
- node_id = node.as_tuple_id()
- if node_id in edges_by_node:
- setattr(
- node,
- edge_name,
- [
- edge.end_node.external_id if direction == "outwards" else edge.start_node.external_id
- for edge in edges_by_node[node_id]
- ],
- )
-
-
-class NodeAPI(
- Generic[T_DomainModel, T_DomainModelWrite, T_DomainModelList, T_DomainModelWriteList],
- NodeReadAPI[T_DomainModel, T_DomainModelList],
- ABC,
-):
- _class_write_list: type[T_DomainModelWriteList]
-
- def _apply(
- self, item: T_DomainModelWrite | Sequence[T_DomainModelWrite], replace: bool = False, write_none: bool = False
- ) -> ResourcesWriteResult:
- if isinstance(item, DomainModelWrite):
- instances = item.to_instances_write(write_none)
- else:
- instances = self._class_write_list(item).to_instances_write(write_none)
- result = self._client.data_modeling.instances.apply(
- nodes=instances.nodes,
- edges=instances.edges,
- auto_create_start_nodes=True,
- auto_create_end_nodes=True,
- replace=replace,
- )
- time_series = TimeSeriesList([])
- if instances.time_series:
- time_series = self._client.time_series.upsert(instances.time_series, mode="patch")
-
- return ResourcesWriteResult(result.nodes, result.edges, time_series)
-
-
-class EdgeAPI(ABC):
- def __init__(self, client: CogniteClient):
- self._client = client
-
- def _list(
- self,
- limit: int = DEFAULT_LIMIT_READ,
- filter_: dm.Filter | None = None,
- ) -> dm.EdgeList:
- return self._client.data_modeling.instances.list("edge", limit=limit, filter=filter_)
-
-
-class EdgePropertyAPI(EdgeAPI, Generic[T_DomainRelation, T_DomainRelationWrite, T_DomainRelationList], ABC):
- _view_id: ClassVar[dm.ViewId]
- _class_type: type[T_DomainRelation]
- _class_write_type: type[T_DomainRelationWrite]
- _class_list: type[T_DomainRelationList]
-
- def _list( # type: ignore[override]
- self,
- limit: int = DEFAULT_LIMIT_READ,
- filter_: dm.Filter | None = None,
- ) -> T_DomainRelationList:
- edges = self._client.data_modeling.instances.list("edge", limit=limit, filter=filter_, sources=[self._view_id])
- return self._class_list([self._class_type.from_instance(edge) for edge in edges]) # type: ignore[misc]
-
-
-class QueryAPI(Generic[T_DomainModelList]):
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- ):
- self._client = client
- self._builder = builder
-
- def _query(self) -> T_DomainModelList:
- self._builder.execute_query(self._client, remove_not_connected=True)
- return self._builder.unpack()
-
-
-def _create_edge_filter(
- edge_type: dm.DirectRelationReference,
- start_node: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- start_node_space: str = DEFAULT_INSTANCE_SPACE,
- end_node: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- space_end_node: str = DEFAULT_INSTANCE_SPACE,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- filter: dm.Filter | None = None,
-) -> dm.Filter:
- filters: list[dm.Filter] = [
- dm.filters.Equals(
- ["edge", "type"],
- {"space": edge_type.space, "externalId": edge_type.external_id},
- )
- ]
- if start_node and isinstance(start_node, str):
- filters.append(
- dm.filters.Equals(["edge", "startNode"], value={"space": start_node_space, "externalId": start_node})
- )
- if start_node and isinstance(start_node, dm.NodeId):
- filters.append(
- dm.filters.Equals(
- ["edge", "startNode"], value=start_node.dump(camel_case=True, include_instance_type=False)
- )
- )
- if start_node and isinstance(start_node, list):
- filters.append(
- dm.filters.In(
- ["edge", "startNode"],
- values=[
- (
- {"space": start_node_space, "externalId": ext_id}
- if isinstance(ext_id, str)
- else ext_id.dump(camel_case=True, include_instance_type=False)
- )
- for ext_id in start_node
- ],
- )
- )
- if end_node and isinstance(end_node, str):
- filters.append(dm.filters.Equals(["edge", "endNode"], value={"space": space_end_node, "externalId": end_node}))
- if end_node and isinstance(end_node, dm.NodeId):
- filters.append(
- dm.filters.Equals(["edge", "endNode"], value=end_node.dump(camel_case=True, include_instance_type=False))
- )
- if end_node and isinstance(end_node, list):
- filters.append(
- dm.filters.In(
- ["edge", "endNode"],
- values=[
- (
- {"space": space_end_node, "externalId": ext_id}
- if isinstance(ext_id, str)
- else ext_id.dump(camel_case=True, include_instance_type=False)
- )
- for ext_id in end_node
- ],
- )
- )
- if external_id_prefix:
- filters.append(dm.filters.Prefix(["edge", "externalId"], value=external_id_prefix))
- if space and isinstance(space, str):
- filters.append(dm.filters.Equals(["edge", "space"], value=space))
- if space and isinstance(space, list):
- filters.append(dm.filters.In(["edge", "space"], values=space))
- if filter:
- filters.append(filter)
- return dm.filters.And(*filters)
-
-
-class GraphQLQueryResponse:
- def __init__(self, data_model_id: dm.DataModelId):
- self._output = GraphQLList([])
- self._data_class_by_type = _GRAPHQL_DATA_CLASS_BY_DATA_MODEL_BY_TYPE[data_model_id]
-
- def parse(self, response: dict[str, Any]) -> GraphQLList:
- if "errors" in response:
- raise RuntimeError(response["errors"])
- _, data = list(response.items())[0]
- self._parse_item(data)
- if "pageInfo" in data:
- self._output.page_info = PageInfo.load(data["pageInfo"])
- return self._output
-
- def _parse_item(self, data: dict[str, Any]) -> None:
- if "items" in data:
- for item in data["items"]:
- self._parse_item(item)
- elif "__typename" in data:
- try:
- item = self._data_class_by_type[data["__typename"]].model_validate(data)
- except KeyError:
- raise ValueError(f"Could not find class for type {data['__typename']}")
- else:
- self._output.append(item)
- else:
- raise RuntimeError("Missing '__typename' in GraphQL response. Cannot determine the type of the response.")
-
-
-_GRAPHQL_DATA_CLASS_BY_DATA_MODEL_BY_TYPE: dict[dm.DataModelId, dict[str, type[GraphQLCore]]] = {
- dm.DataModelId("power-models", "Windmill", "1"): {
- "Blade": data_classes.BladeGraphQL,
- "Gearbox": data_classes.GearboxGraphQL,
- "Generator": data_classes.GeneratorGraphQL,
- "HighSpeedShaft": data_classes.HighSpeedShaftGraphQL,
- "MainShaft": data_classes.MainShaftGraphQL,
- "Metmast": data_classes.MetmastGraphQL,
- "Nacelle": data_classes.NacelleGraphQL,
- "PowerInverter": data_classes.PowerInverterGraphQL,
- "Rotor": data_classes.RotorGraphQL,
- "SensorPosition": data_classes.SensorPositionGraphQL,
- "Windmill": data_classes.WindmillGraphQL,
- },
-}
diff --git a/examples/windmill/_api/blade.py b/examples/windmill/_api/blade.py
deleted file mode 100644
index ee2a538cb..000000000
--- a/examples/windmill/_api/blade.py
+++ /dev/null
@@ -1,573 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Blade,
- BladeWrite,
- BladeFields,
- BladeList,
- BladeWriteList,
- BladeTextFields,
- SensorPosition,
-)
-from windmill.data_classes._blade import (
- BladeQuery,
- _BLADE_PROPERTIES_BY_FIELD,
- _create_blade_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.blade_sensor_positions import BladeSensorPositionsAPI
-from windmill._api.blade_query import BladeQueryAPI
-
-
-class BladeAPI(NodeAPI[Blade, BladeWrite, BladeList, BladeWriteList]):
- _view_id = dm.ViewId("power-models", "Blade", "1")
- _properties_by_field = _BLADE_PROPERTIES_BY_FIELD
- _class_type = Blade
- _class_list = BladeList
- _class_write_list = BladeWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.sensor_positions_edge = BladeSensorPositionsAPI(client)
-
- def __call__(
- self,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> BladeQueryAPI[BladeList]:
- """Query starting at blades.
-
- Args:
- is_damaged: The is damaged to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of blades to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for blades.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_blade_filter(
- self._view_id,
- is_damaged,
- name,
- name_prefix,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(BladeList)
- return BladeQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- blade: BladeWrite | Sequence[BladeWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) blades.
-
- Note: This method iterates through all nodes and timeseries linked to blade and creates them including the edges
- between the nodes. For example, if any of `sensor_positions` are set, then these
- nodes as well as any nodes linked to them, and all the edges linking these nodes will be created.
-
- Args:
- blade: Blade or sequence of blades to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new blade:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import BladeWrite
- >>> client = WindmillClient()
- >>> blade = BladeWrite(external_id="my_blade", ...)
- >>> result = client.blade.apply(blade)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.blade.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(blade, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more blade.
-
- Args:
- external_id: External id of the blade to delete.
- space: The space where all the blade are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete blade by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.blade.delete("my_blade")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.blade.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Blade | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> BladeList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Blade | BladeList | None:
- """Retrieve one or more blades by id(s).
-
- Args:
- external_id: External id or list of external ids of the blades.
- space: The space where all the blades are located.
-
- Returns:
- The requested blades.
-
- Examples:
-
- Retrieve blade by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> blade = client.blade.retrieve("my_blade")
-
- """
- return self._retrieve(
- external_id,
- space,
- retrieve_edges=True,
- edge_api_name_type_direction_view_id_penta=[
- (
- self.sensor_positions_edge,
- "sensor_positions",
- dm.DirectRelationReference("power-models", "Blade.sensor_positions"),
- "outwards",
- dm.ViewId("power-models", "SensorPosition", "1"),
- ),
- ],
- )
-
- def search(
- self,
- query: str,
- properties: BladeTextFields | SequenceNotStr[BladeTextFields] | None = None,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: BladeFields | SequenceNotStr[BladeFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> BladeList:
- """Search blades
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- is_damaged: The is damaged to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of blades to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results blades matching the query.
-
- Examples:
-
- Search for 'my_blade' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> blades = client.blade.search('my_blade')
-
- """
- filter_ = _create_blade_filter(
- self._view_id,
- is_damaged,
- name,
- name_prefix,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: BladeFields | SequenceNotStr[BladeFields] | None = None,
- query: str | None = None,
- search_property: BladeTextFields | SequenceNotStr[BladeTextFields] | None = None,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: BladeFields | SequenceNotStr[BladeFields] | None = None,
- query: str | None = None,
- search_property: BladeTextFields | SequenceNotStr[BladeTextFields] | None = None,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: BladeFields | SequenceNotStr[BladeFields],
- property: BladeFields | SequenceNotStr[BladeFields] | None = None,
- query: str | None = None,
- search_property: BladeTextFields | SequenceNotStr[BladeTextFields] | None = None,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: BladeFields | SequenceNotStr[BladeFields] | None = None,
- property: BladeFields | SequenceNotStr[BladeFields] | None = None,
- query: str | None = None,
- search_property: BladeTextFields | SequenceNotStr[BladeTextFields] | None = None,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across blades
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- query: The query to search for in the text field.
- search_property: The text field to search in.
- is_damaged: The is damaged to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of blades to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count blades in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.blade.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_blade_filter(
- self._view_id,
- is_damaged,
- name,
- name_prefix,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=query,
- search_properties=search_property, # type: ignore[arg-type]
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: BladeFields,
- interval: float,
- query: str | None = None,
- search_property: BladeTextFields | SequenceNotStr[BladeTextFields] | None = None,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for blades
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- query: The query to search for in the text field.
- search_property: The text field to search in.
- is_damaged: The is damaged to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of blades to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_blade_filter(
- self._view_id,
- is_damaged,
- name,
- name_prefix,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- query,
- search_property, # type: ignore[arg-type]
- limit,
- filter_,
- )
-
- def query(self) -> BladeQuery:
- """Start a query for blades."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return BladeQuery(self._client)
-
- def select(self) -> BladeQuery:
- """Start selecting from blades."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return BladeQuery(self._client)
-
- def list(
- self,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: BladeFields | Sequence[BladeFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- retrieve_connections: Literal["skip", "identifier", "full"] = "skip",
- ) -> BladeList:
- """List/filter blades
-
- Args:
- is_damaged: The is damaged to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of blades to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
- retrieve_connections: Whether to retrieve `sensor_positions` for the blades. Defaults to 'skip'.
- 'skip' will not retrieve any connections, 'identifier' will only retrieve the identifier of the connected items, and 'full' will retrieve the full connected items.
-
- Returns:
- List of requested blades
-
- Examples:
-
- List blades and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> blades = client.blade.list(limit=5)
-
- """
- filter_ = _create_blade_filter(
- self._view_id,
- is_damaged,
- name,
- name_prefix,
- external_id_prefix,
- space,
- filter,
- )
-
- if retrieve_connections == "skip":
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- builder = DataClassQueryBuilder(BladeList)
- has_data = dm.filters.HasData(views=[self._view_id])
- builder.append(
- NodeQueryStep(
- builder.create_name(None),
- dm.query.NodeResultSetExpression(
- filter=dm.filters.And(filter_, has_data) if filter_ else has_data,
- sort=self._create_sort(sort_by, direction, sort), # type: ignore[arg-type]
- ),
- Blade,
- max_retrieve_limit=limit,
- raw_filter=filter_,
- )
- )
- from_root = builder.get_from()
- edge_sensor_positions = builder.create_name(from_root)
- builder.append(
- EdgeQueryStep(
- edge_sensor_positions,
- dm.query.EdgeResultSetExpression(
- from_=from_root,
- direction="outwards",
- chain_to="destination",
- ),
- )
- )
- if retrieve_connections == "full":
- builder.append(
- NodeQueryStep(
- builder.create_name(edge_sensor_positions),
- dm.query.NodeResultSetExpression(
- from_=edge_sensor_positions,
- filter=dm.filters.HasData(views=[SensorPosition._view_id]),
- ),
- SensorPosition,
- )
- )
- # We know that that all nodes are connected as it is not possible to filter on connections
- builder.execute_query(self._client, remove_not_connected=False)
- return builder.unpack()
diff --git a/examples/windmill/_api/blade_query.py b/examples/windmill/_api/blade_query.py
deleted file mode 100644
index ba5770932..000000000
--- a/examples/windmill/_api/blade_query.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Blade,
-)
-from windmill.data_classes._sensor_position import (
- SensorPosition,
- _create_sensor_position_filter,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-if TYPE_CHECKING:
- from windmill._api.sensor_position_query import SensorPositionQueryAPI
-
-
-class BladeQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Blade", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Blade,
- max_retrieve_limit=limit,
- )
- )
-
- def sensor_positions(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- external_id_prefix_edge: str | None = None,
- space_edge: str | list[str] | None = None,
- filter: dm.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ) -> SensorPositionQueryAPI[T_DomainModelList]:
- """Query along the sensor position edges of the blade.
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- external_id_prefix_edge: The prefix of the external ID to filter on.
- space_edge: The space to filter on.
- filter: (Advanced) Filter applied to node. If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- limit: Maximum number of sensor position edges to return. Defaults to 3. Set to -1, float("inf") or None
- to return all items.
-
- Returns:
- SensorPositionQueryAPI: The query API for the sensor position.
- """
- from .sensor_position_query import SensorPositionQueryAPI
-
- # from is a string as we added a node query step in the __init__ method
- from_ = cast(str, self._builder.get_from())
- edge_filter = _create_edge_filter(
- dm.DirectRelationReference("power-models", "Blade.sensor_positions"),
- external_id_prefix=external_id_prefix_edge,
- space=space_edge,
- )
- self._builder.append(
- EdgeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.EdgeResultSetExpression(
- filter=edge_filter,
- from_=from_,
- direction="outwards",
- ),
- max_retrieve_limit=limit,
- )
- )
-
- view_id = SensorPositionQueryAPI._view_id
- has_data = dm.filters.HasData(views=[view_id])
- node_filer = _create_sensor_position_filter(
- view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- return SensorPositionQueryAPI(self._client, self._builder, node_filer, limit)
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/blade_sensor_positions.py b/examples/windmill/_api/blade_sensor_positions.py
deleted file mode 100644
index 0856d45c1..000000000
--- a/examples/windmill/_api/blade_sensor_positions.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from __future__ import annotations
-
-
-from cognite.client import data_modeling as dm
-
-from windmill._api._core import DEFAULT_LIMIT_READ, EdgeAPI, _create_edge_filter
-from windmill.data_classes._core import DEFAULT_INSTANCE_SPACE
-
-
-class BladeSensorPositionsAPI(EdgeAPI):
- def list(
- self,
- from_blade: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- from_blade_space: str = DEFAULT_INSTANCE_SPACE,
- to_sensor_position: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- to_sensor_position_space: str = DEFAULT_INSTANCE_SPACE,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit=DEFAULT_LIMIT_READ,
- ) -> dm.EdgeList:
- """List sensor position edges of a blade.
-
- Args:
- from_blade: ID of the source blade.
- from_blade_space: Location of the blades.
- to_sensor_position: ID of the target sensor position.
- to_sensor_position_space: Location of the sensor positions.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor position edges to return. Defaults to 25. Set to -1, float("inf") or None
- to return all items.
-
- Returns:
- The requested sensor position edges.
-
- Examples:
-
- List 5 sensor position edges connected to "my_blade":
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> blade = client.blade.sensor_positions_edge.list("my_blade", limit=5)
-
- """
- filter_ = _create_edge_filter(
- dm.DirectRelationReference("power-models", "Blade.sensor_positions"),
- from_blade,
- from_blade_space,
- to_sensor_position,
- to_sensor_position_space,
- external_id_prefix,
- space,
- )
- return self._list(filter_=filter_, limit=limit)
diff --git a/examples/windmill/_api/gearbox.py b/examples/windmill/_api/gearbox.py
deleted file mode 100644
index 07c5b5c49..000000000
--- a/examples/windmill/_api/gearbox.py
+++ /dev/null
@@ -1,446 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Gearbox,
- GearboxWrite,
- GearboxFields,
- GearboxList,
- GearboxWriteList,
- GearboxTextFields,
-)
-from windmill.data_classes._gearbox import (
- GearboxQuery,
- _GEARBOX_PROPERTIES_BY_FIELD,
- _create_gearbox_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.gearbox_displacement_x import GearboxDisplacementXAPI
-from windmill._api.gearbox_displacement_y import GearboxDisplacementYAPI
-from windmill._api.gearbox_displacement_z import GearboxDisplacementZAPI
-from windmill._api.gearbox_query import GearboxQueryAPI
-
-
-class GearboxAPI(NodeAPI[Gearbox, GearboxWrite, GearboxList, GearboxWriteList]):
- _view_id = dm.ViewId("power-models", "Gearbox", "1")
- _properties_by_field = _GEARBOX_PROPERTIES_BY_FIELD
- _class_type = Gearbox
- _class_list = GearboxList
- _class_write_list = GearboxWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.displacement_x = GearboxDisplacementXAPI(client, self._view_id)
- self.displacement_y = GearboxDisplacementYAPI(client, self._view_id)
- self.displacement_z = GearboxDisplacementZAPI(client, self._view_id)
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> GearboxQueryAPI[GearboxList]:
- """Query starting at gearboxes.
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for gearboxes.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(GearboxList)
- return GearboxQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- gearbox: GearboxWrite | Sequence[GearboxWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) gearboxes.
-
- Args:
- gearbox: Gearbox or sequence of gearboxes to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new gearbox:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import GearboxWrite
- >>> client = WindmillClient()
- >>> gearbox = GearboxWrite(external_id="my_gearbox", ...)
- >>> result = client.gearbox.apply(gearbox)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.gearbox.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(gearbox, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more gearbox.
-
- Args:
- external_id: External id of the gearbox to delete.
- space: The space where all the gearbox are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete gearbox by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.gearbox.delete("my_gearbox")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.gearbox.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Gearbox | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> GearboxList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Gearbox | GearboxList | None:
- """Retrieve one or more gearboxes by id(s).
-
- Args:
- external_id: External id or list of external ids of the gearboxes.
- space: The space where all the gearboxes are located.
-
- Returns:
- The requested gearboxes.
-
- Examples:
-
- Retrieve gearbox by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox = client.gearbox.retrieve("my_gearbox")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: GearboxTextFields | SequenceNotStr[GearboxTextFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: GearboxFields | SequenceNotStr[GearboxFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> GearboxList:
- """Search gearboxes
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results gearboxes matching the query.
-
- Examples:
-
- Search for 'my_gearbox' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.search('my_gearbox')
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: GearboxFields | SequenceNotStr[GearboxFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: GearboxFields | SequenceNotStr[GearboxFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: GearboxFields | SequenceNotStr[GearboxFields],
- property: GearboxFields | SequenceNotStr[GearboxFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: GearboxFields | SequenceNotStr[GearboxFields] | None = None,
- property: GearboxFields | SequenceNotStr[GearboxFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across gearboxes
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count gearboxes in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.gearbox.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: GearboxFields,
- interval: float,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for gearboxes
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> GearboxQuery:
- """Start a query for gearboxes."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return GearboxQuery(self._client)
-
- def select(self) -> GearboxQuery:
- """Start selecting from gearboxes."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return GearboxQuery(self._client)
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: GearboxFields | Sequence[GearboxFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> GearboxList:
- """List/filter gearboxes
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested gearboxes
-
- Examples:
-
- List gearboxes and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.list(limit=5)
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/gearbox_displacement_x.py b/examples/windmill/_api/gearbox_displacement_x.py
deleted file mode 100644
index a2c725a34..000000000
--- a/examples/windmill/_api/gearbox_displacement_x.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._gearbox import _create_gearbox_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["displacement_x", "displacement_y", "displacement_z"]
-
-
-class GearboxDisplacementXQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `gearbox.displacement_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_x(external_id="my_displacement_x").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `gearbox.displacement_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_x(external_id="my_displacement_x").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "displacement_x",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `gearbox.displacement_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to displacement_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_x(external_id="my_displacement_x").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "displacement_x",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `gearbox.displacement_x` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to displacement_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_displacement_x' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_x(
- ... external_id="my_displacement_x").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "displacement_x"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_displacement_x(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "displacement_x":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class GearboxDisplacementXAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> GearboxDisplacementXQuery:
- """Query timeseries `gearbox.displacement_x`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the gearbox.displacement_x timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 gearbox.displacement_x timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.displacement_x(limit=5).retrieve()
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return GearboxDisplacementXQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `gearbox.displacement_x`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries gearbox.displacement_x.
-
- Examples:
-
- List gearbox.displacement_x and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.displacement_x.list(limit=5)
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_displacement_x(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_displacement_x(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "displacement_x",
-) -> dict[str, list[str]]:
- properties = {"displacement_x"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("displacement_x"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["displacement_x"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/gearbox_displacement_y.py b/examples/windmill/_api/gearbox_displacement_y.py
deleted file mode 100644
index 84d9c6a6c..000000000
--- a/examples/windmill/_api/gearbox_displacement_y.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._gearbox import _create_gearbox_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["displacement_x", "displacement_y", "displacement_z"]
-
-
-class GearboxDisplacementYQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `gearbox.displacement_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_y(external_id="my_displacement_y").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `gearbox.displacement_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_y(external_id="my_displacement_y").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "displacement_y",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `gearbox.displacement_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to displacement_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_y(external_id="my_displacement_y").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "displacement_y",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `gearbox.displacement_y` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to displacement_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_displacement_y' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_y(
- ... external_id="my_displacement_y").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "displacement_y"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_displacement_y(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "displacement_y":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class GearboxDisplacementYAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> GearboxDisplacementYQuery:
- """Query timeseries `gearbox.displacement_y`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the gearbox.displacement_y timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 gearbox.displacement_y timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.displacement_y(limit=5).retrieve()
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return GearboxDisplacementYQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `gearbox.displacement_y`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries gearbox.displacement_y.
-
- Examples:
-
- List gearbox.displacement_y and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.displacement_y.list(limit=5)
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_displacement_y(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_displacement_y(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "displacement_y",
-) -> dict[str, list[str]]:
- properties = {"displacement_y"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("displacement_y"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["displacement_y"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/gearbox_displacement_z.py b/examples/windmill/_api/gearbox_displacement_z.py
deleted file mode 100644
index 7c05b15f1..000000000
--- a/examples/windmill/_api/gearbox_displacement_z.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._gearbox import _create_gearbox_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["displacement_x", "displacement_y", "displacement_z"]
-
-
-class GearboxDisplacementZQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `gearbox.displacement_z` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_z' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_z(external_id="my_displacement_z").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `gearbox.displacement_z` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_z' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_z(external_id="my_displacement_z").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "displacement_z",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `gearbox.displacement_z` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to displacement_z
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_displacement_z' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_z(external_id="my_displacement_z").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "displacement_z",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `gearbox.displacement_z` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to displacement_z
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_displacement_z' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> gearbox_datapoints = client.gearbox.displacement_z(
- ... external_id="my_displacement_z").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "displacement_z"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_displacement_z(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "displacement_z":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class GearboxDisplacementZAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> GearboxDisplacementZQuery:
- """Query timeseries `gearbox.displacement_z`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the gearbox.displacement_z timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 gearbox.displacement_z timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.displacement_z(limit=5).retrieve()
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return GearboxDisplacementZQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `gearbox.displacement_z`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of gearboxes to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries gearbox.displacement_z.
-
- Examples:
-
- List gearbox.displacement_z and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> gearboxes = client.gearbox.displacement_z.list(limit=5)
-
- """
- filter_ = _create_gearbox_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_displacement_z(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_displacement_z(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "displacement_z",
-) -> dict[str, list[str]]:
- properties = {"displacement_z"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("displacement_z"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["displacement_z"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/gearbox_query.py b/examples/windmill/_api/gearbox_query.py
deleted file mode 100644
index 42fb4adcf..000000000
--- a/examples/windmill/_api/gearbox_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Gearbox,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class GearboxQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Gearbox", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Gearbox,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/generator.py b/examples/windmill/_api/generator.py
deleted file mode 100644
index d4d3ad9d7..000000000
--- a/examples/windmill/_api/generator.py
+++ /dev/null
@@ -1,444 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Generator,
- GeneratorWrite,
- GeneratorFields,
- GeneratorList,
- GeneratorWriteList,
- GeneratorTextFields,
-)
-from windmill.data_classes._generator import (
- GeneratorQuery,
- _GENERATOR_PROPERTIES_BY_FIELD,
- _create_generator_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.generator_generator_speed_controller import GeneratorGeneratorSpeedControllerAPI
-from windmill._api.generator_generator_speed_controller_reference import GeneratorGeneratorSpeedControllerReferenceAPI
-from windmill._api.generator_query import GeneratorQueryAPI
-
-
-class GeneratorAPI(NodeAPI[Generator, GeneratorWrite, GeneratorList, GeneratorWriteList]):
- _view_id = dm.ViewId("power-models", "Generator", "1")
- _properties_by_field = _GENERATOR_PROPERTIES_BY_FIELD
- _class_type = Generator
- _class_list = GeneratorList
- _class_write_list = GeneratorWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.generator_speed_controller = GeneratorGeneratorSpeedControllerAPI(client, self._view_id)
- self.generator_speed_controller_reference = GeneratorGeneratorSpeedControllerReferenceAPI(client, self._view_id)
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> GeneratorQueryAPI[GeneratorList]:
- """Query starting at generators.
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for generators.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(GeneratorList)
- return GeneratorQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- generator: GeneratorWrite | Sequence[GeneratorWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) generators.
-
- Args:
- generator: Generator or sequence of generators to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new generator:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import GeneratorWrite
- >>> client = WindmillClient()
- >>> generator = GeneratorWrite(external_id="my_generator", ...)
- >>> result = client.generator.apply(generator)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.generator.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(generator, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more generator.
-
- Args:
- external_id: External id of the generator to delete.
- space: The space where all the generator are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete generator by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.generator.delete("my_generator")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.generator.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Generator | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> GeneratorList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Generator | GeneratorList | None:
- """Retrieve one or more generators by id(s).
-
- Args:
- external_id: External id or list of external ids of the generators.
- space: The space where all the generators are located.
-
- Returns:
- The requested generators.
-
- Examples:
-
- Retrieve generator by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator = client.generator.retrieve("my_generator")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: GeneratorTextFields | SequenceNotStr[GeneratorTextFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: GeneratorFields | SequenceNotStr[GeneratorFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> GeneratorList:
- """Search generators
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results generators matching the query.
-
- Examples:
-
- Search for 'my_generator' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generators = client.generator.search('my_generator')
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: GeneratorFields | SequenceNotStr[GeneratorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: GeneratorFields | SequenceNotStr[GeneratorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: GeneratorFields | SequenceNotStr[GeneratorFields],
- property: GeneratorFields | SequenceNotStr[GeneratorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: GeneratorFields | SequenceNotStr[GeneratorFields] | None = None,
- property: GeneratorFields | SequenceNotStr[GeneratorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across generators
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count generators in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.generator.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: GeneratorFields,
- interval: float,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for generators
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> GeneratorQuery:
- """Start a query for generators."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return GeneratorQuery(self._client)
-
- def select(self) -> GeneratorQuery:
- """Start selecting from generators."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return GeneratorQuery(self._client)
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: GeneratorFields | Sequence[GeneratorFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> GeneratorList:
- """List/filter generators
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested generators
-
- Examples:
-
- List generators and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generators = client.generator.list(limit=5)
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/generator_generator_speed_controller.py b/examples/windmill/_api/generator_generator_speed_controller.py
deleted file mode 100644
index c2f8434ce..000000000
--- a/examples/windmill/_api/generator_generator_speed_controller.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._generator import _create_generator_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["generator_speed_controller", "generator_speed_controller_reference"]
-
-
-class GeneratorGeneratorSpeedControllerQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `generator.generator_speed_controller` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_generator_speed_controller' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller(external_id="my_generator_speed_controller").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `generator.generator_speed_controller` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_generator_speed_controller' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller(external_id="my_generator_speed_controller").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "generator_speed_controller",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `generator.generator_speed_controller` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to generator_speed_controller
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_generator_speed_controller' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller(external_id="my_generator_speed_controller").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "generator_speed_controller",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `generator.generator_speed_controller` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to generator_speed_controller
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_generator_speed_controller' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller(
- ... external_id="my_generator_speed_controller").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "generator_speed_controller"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_generator_speed_controller(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "generator_speed_controller":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class GeneratorGeneratorSpeedControllerAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> GeneratorGeneratorSpeedControllerQuery:
- """Query timeseries `generator.generator_speed_controller`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the generator.generator_speed_controller timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 generator.generator_speed_controller timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generators = client.generator.generator_speed_controller(limit=5).retrieve()
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return GeneratorGeneratorSpeedControllerQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `generator.generator_speed_controller`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries generator.generator_speed_controller.
-
- Examples:
-
- List generator.generator_speed_controller and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generators = client.generator.generator_speed_controller.list(limit=5)
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_generator_speed_controller(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_generator_speed_controller(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "generator_speed_controller",
-) -> dict[str, list[str]]:
- properties = {"generator_speed_controller"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("generator_speed_controller"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["generator_speed_controller"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/generator_generator_speed_controller_reference.py b/examples/windmill/_api/generator_generator_speed_controller_reference.py
deleted file mode 100644
index 0f3ce12df..000000000
--- a/examples/windmill/_api/generator_generator_speed_controller_reference.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._generator import _create_generator_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["generator_speed_controller", "generator_speed_controller_reference"]
-
-
-class GeneratorGeneratorSpeedControllerReferenceQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `generator.generator_speed_controller_reference` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_generator_speed_controller_reference' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller_reference(external_id="my_generator_speed_controller_reference").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `generator.generator_speed_controller_reference` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_generator_speed_controller_reference' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller_reference(external_id="my_generator_speed_controller_reference").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "generator_speed_controller_reference",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `generator.generator_speed_controller_reference` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to generator_speed_controller_reference
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_generator_speed_controller_reference' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller_reference(external_id="my_generator_speed_controller_reference").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "generator_speed_controller_reference",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `generator.generator_speed_controller_reference` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to generator_speed_controller_reference
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_generator_speed_controller_reference' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> generator_datapoints = client.generator.generator_speed_controller_reference(
- ... external_id="my_generator_speed_controller_reference").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "generator_speed_controller_reference"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_generator_speed_controller_reference(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "generator_speed_controller_reference":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class GeneratorGeneratorSpeedControllerReferenceAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> GeneratorGeneratorSpeedControllerReferenceQuery:
- """Query timeseries `generator.generator_speed_controller_reference`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the generator.generator_speed_controller_reference timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 generator.generator_speed_controller_reference timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generators = client.generator.generator_speed_controller_reference(limit=5).retrieve()
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return GeneratorGeneratorSpeedControllerReferenceQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `generator.generator_speed_controller_reference`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of generators to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries generator.generator_speed_controller_reference.
-
- Examples:
-
- List generator.generator_speed_controller_reference and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> generators = client.generator.generator_speed_controller_reference.list(limit=5)
-
- """
- filter_ = _create_generator_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_generator_speed_controller_reference(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_generator_speed_controller_reference(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "generator_speed_controller_reference",
-) -> dict[str, list[str]]:
- properties = {"generator_speed_controller_reference"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("generator_speed_controller_reference"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["generator_speed_controller_reference"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/generator_query.py b/examples/windmill/_api/generator_query.py
deleted file mode 100644
index 2b8cec24b..000000000
--- a/examples/windmill/_api/generator_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Generator,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class GeneratorQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Generator", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Generator,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/high_speed_shaft.py b/examples/windmill/_api/high_speed_shaft.py
deleted file mode 100644
index 50a2b72bd..000000000
--- a/examples/windmill/_api/high_speed_shaft.py
+++ /dev/null
@@ -1,446 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- HighSpeedShaft,
- HighSpeedShaftWrite,
- HighSpeedShaftFields,
- HighSpeedShaftList,
- HighSpeedShaftWriteList,
- HighSpeedShaftTextFields,
-)
-from windmill.data_classes._high_speed_shaft import (
- HighSpeedShaftQuery,
- _HIGHSPEEDSHAFT_PROPERTIES_BY_FIELD,
- _create_high_speed_shaft_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.high_speed_shaft_bending_moment_y import HighSpeedShaftBendingMomentYAPI
-from windmill._api.high_speed_shaft_bending_monent_x import HighSpeedShaftBendingMonentXAPI
-from windmill._api.high_speed_shaft_torque import HighSpeedShaftTorqueAPI
-from windmill._api.high_speed_shaft_query import HighSpeedShaftQueryAPI
-
-
-class HighSpeedShaftAPI(NodeAPI[HighSpeedShaft, HighSpeedShaftWrite, HighSpeedShaftList, HighSpeedShaftWriteList]):
- _view_id = dm.ViewId("power-models", "HighSpeedShaft", "1")
- _properties_by_field = _HIGHSPEEDSHAFT_PROPERTIES_BY_FIELD
- _class_type = HighSpeedShaft
- _class_list = HighSpeedShaftList
- _class_write_list = HighSpeedShaftWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.bending_moment_y = HighSpeedShaftBendingMomentYAPI(client, self._view_id)
- self.bending_monent_x = HighSpeedShaftBendingMonentXAPI(client, self._view_id)
- self.torque = HighSpeedShaftTorqueAPI(client, self._view_id)
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> HighSpeedShaftQueryAPI[HighSpeedShaftList]:
- """Query starting at high speed shafts.
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for high speed shafts.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(HighSpeedShaftList)
- return HighSpeedShaftQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- high_speed_shaft: HighSpeedShaftWrite | Sequence[HighSpeedShaftWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) high speed shafts.
-
- Args:
- high_speed_shaft: High speed shaft or sequence of high speed shafts to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new high_speed_shaft:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import HighSpeedShaftWrite
- >>> client = WindmillClient()
- >>> high_speed_shaft = HighSpeedShaftWrite(external_id="my_high_speed_shaft", ...)
- >>> result = client.high_speed_shaft.apply(high_speed_shaft)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.high_speed_shaft.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(high_speed_shaft, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more high speed shaft.
-
- Args:
- external_id: External id of the high speed shaft to delete.
- space: The space where all the high speed shaft are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete high_speed_shaft by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.high_speed_shaft.delete("my_high_speed_shaft")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.high_speed_shaft.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> HighSpeedShaft | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> HighSpeedShaftList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> HighSpeedShaft | HighSpeedShaftList | None:
- """Retrieve one or more high speed shafts by id(s).
-
- Args:
- external_id: External id or list of external ids of the high speed shafts.
- space: The space where all the high speed shafts are located.
-
- Returns:
- The requested high speed shafts.
-
- Examples:
-
- Retrieve high_speed_shaft by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft = client.high_speed_shaft.retrieve("my_high_speed_shaft")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: HighSpeedShaftTextFields | SequenceNotStr[HighSpeedShaftTextFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> HighSpeedShaftList:
- """Search high speed shafts
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results high speed shafts matching the query.
-
- Examples:
-
- Search for 'my_high_speed_shaft' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.search('my_high_speed_shaft')
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields],
- property: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields] | None = None,
- property: HighSpeedShaftFields | SequenceNotStr[HighSpeedShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across high speed shafts
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count high speed shafts in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.high_speed_shaft.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: HighSpeedShaftFields,
- interval: float,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for high speed shafts
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> HighSpeedShaftQuery:
- """Start a query for high speed shafts."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return HighSpeedShaftQuery(self._client)
-
- def select(self) -> HighSpeedShaftQuery:
- """Start selecting from high speed shafts."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return HighSpeedShaftQuery(self._client)
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: HighSpeedShaftFields | Sequence[HighSpeedShaftFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> HighSpeedShaftList:
- """List/filter high speed shafts
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested high speed shafts
-
- Examples:
-
- List high speed shafts and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.list(limit=5)
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/high_speed_shaft_bending_moment_y.py b/examples/windmill/_api/high_speed_shaft_bending_moment_y.py
deleted file mode 100644
index a4cacd371..000000000
--- a/examples/windmill/_api/high_speed_shaft_bending_moment_y.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._high_speed_shaft import _create_high_speed_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_moment_y", "bending_monent_x", "torque"]
-
-
-class HighSpeedShaftBendingMomentYQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `high_speed_shaft.bending_moment_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_moment_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_moment_y(external_id="my_bending_moment_y").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `high_speed_shaft.bending_moment_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_moment_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_moment_y(external_id="my_bending_moment_y").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_moment_y",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `high_speed_shaft.bending_moment_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_moment_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_moment_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_moment_y(external_id="my_bending_moment_y").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_moment_y",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `high_speed_shaft.bending_moment_y` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_moment_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_bending_moment_y' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_moment_y(
- ... external_id="my_bending_moment_y").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "bending_moment_y"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_bending_moment_y(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "bending_moment_y":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class HighSpeedShaftBendingMomentYAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> HighSpeedShaftBendingMomentYQuery:
- """Query timeseries `high_speed_shaft.bending_moment_y`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the high_speed_shaft.bending_moment_y timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 high_speed_shaft.bending_moment_y timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.bending_moment_y(limit=5).retrieve()
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return HighSpeedShaftBendingMomentYQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `high_speed_shaft.bending_moment_y`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries high_speed_shaft.bending_moment_y.
-
- Examples:
-
- List high_speed_shaft.bending_moment_y and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.bending_moment_y.list(limit=5)
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_bending_moment_y(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_bending_moment_y(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "bending_moment_y",
-) -> dict[str, list[str]]:
- properties = {"bending_moment_y"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("bending_moment_y"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["bending_moment_y"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/high_speed_shaft_bending_monent_x.py b/examples/windmill/_api/high_speed_shaft_bending_monent_x.py
deleted file mode 100644
index 606229d8a..000000000
--- a/examples/windmill/_api/high_speed_shaft_bending_monent_x.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._high_speed_shaft import _create_high_speed_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_moment_y", "bending_monent_x", "torque"]
-
-
-class HighSpeedShaftBendingMonentXQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `high_speed_shaft.bending_monent_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_monent_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_monent_x(external_id="my_bending_monent_x").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `high_speed_shaft.bending_monent_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_monent_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_monent_x(external_id="my_bending_monent_x").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_monent_x",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `high_speed_shaft.bending_monent_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_monent_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_monent_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_monent_x(external_id="my_bending_monent_x").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_monent_x",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `high_speed_shaft.bending_monent_x` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_monent_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_bending_monent_x' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.bending_monent_x(
- ... external_id="my_bending_monent_x").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "bending_monent_x"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_bending_monent_x(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "bending_monent_x":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class HighSpeedShaftBendingMonentXAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> HighSpeedShaftBendingMonentXQuery:
- """Query timeseries `high_speed_shaft.bending_monent_x`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the high_speed_shaft.bending_monent_x timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 high_speed_shaft.bending_monent_x timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.bending_monent_x(limit=5).retrieve()
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return HighSpeedShaftBendingMonentXQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `high_speed_shaft.bending_monent_x`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries high_speed_shaft.bending_monent_x.
-
- Examples:
-
- List high_speed_shaft.bending_monent_x and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.bending_monent_x.list(limit=5)
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_bending_monent_x(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_bending_monent_x(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "bending_monent_x",
-) -> dict[str, list[str]]:
- properties = {"bending_monent_x"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("bending_monent_x"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["bending_monent_x"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/high_speed_shaft_query.py b/examples/windmill/_api/high_speed_shaft_query.py
deleted file mode 100644
index 7823ff40e..000000000
--- a/examples/windmill/_api/high_speed_shaft_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- HighSpeedShaft,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class HighSpeedShaftQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "HighSpeedShaft", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=HighSpeedShaft,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/high_speed_shaft_torque.py b/examples/windmill/_api/high_speed_shaft_torque.py
deleted file mode 100644
index 4ff69ff64..000000000
--- a/examples/windmill/_api/high_speed_shaft_torque.py
+++ /dev/null
@@ -1,491 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._high_speed_shaft import _create_high_speed_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_moment_y", "bending_monent_x", "torque"]
-
-
-class HighSpeedShaftTorqueQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `high_speed_shaft.torque` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_torque' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.torque(external_id="my_torque").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `high_speed_shaft.torque` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_torque' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.torque(external_id="my_torque").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "torque",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `high_speed_shaft.torque` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to torque
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_torque' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.torque(external_id="my_torque").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "torque",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `high_speed_shaft.torque` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to torque
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_torque' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> high_speed_shaft_datapoints = client.high_speed_shaft.torque(
- ... external_id="my_torque").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "torque"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_torque(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "torque":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class HighSpeedShaftTorqueAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> HighSpeedShaftTorqueQuery:
- """Query timeseries `high_speed_shaft.torque`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the high_speed_shaft.torque timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 high_speed_shaft.torque timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.torque(limit=5).retrieve()
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return HighSpeedShaftTorqueQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `high_speed_shaft.torque`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of high speed shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries high_speed_shaft.torque.
-
- Examples:
-
- List high_speed_shaft.torque and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> high_speed_shafts = client.high_speed_shaft.torque.list(limit=5)
-
- """
- filter_ = _create_high_speed_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_torque(self._client, self._view_id, filter_, limit)
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_torque(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "torque",
-) -> dict[str, list[str]]:
- properties = {"torque"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("torque"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["torque"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/main_shaft.py b/examples/windmill/_api/main_shaft.py
deleted file mode 100644
index f7d8a91d0..000000000
--- a/examples/windmill/_api/main_shaft.py
+++ /dev/null
@@ -1,450 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- MainShaft,
- MainShaftWrite,
- MainShaftFields,
- MainShaftList,
- MainShaftWriteList,
- MainShaftTextFields,
-)
-from windmill.data_classes._main_shaft import (
- MainShaftQuery,
- _MAINSHAFT_PROPERTIES_BY_FIELD,
- _create_main_shaft_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.main_shaft_bending_x import MainShaftBendingXAPI
-from windmill._api.main_shaft_bending_y import MainShaftBendingYAPI
-from windmill._api.main_shaft_calculated_tilt_moment import MainShaftCalculatedTiltMomentAPI
-from windmill._api.main_shaft_calculated_yaw_moment import MainShaftCalculatedYawMomentAPI
-from windmill._api.main_shaft_torque import MainShaftTorqueAPI
-from windmill._api.main_shaft_query import MainShaftQueryAPI
-
-
-class MainShaftAPI(NodeAPI[MainShaft, MainShaftWrite, MainShaftList, MainShaftWriteList]):
- _view_id = dm.ViewId("power-models", "MainShaft", "1")
- _properties_by_field = _MAINSHAFT_PROPERTIES_BY_FIELD
- _class_type = MainShaft
- _class_list = MainShaftList
- _class_write_list = MainShaftWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.bending_x = MainShaftBendingXAPI(client, self._view_id)
- self.bending_y = MainShaftBendingYAPI(client, self._view_id)
- self.calculated_tilt_moment = MainShaftCalculatedTiltMomentAPI(client, self._view_id)
- self.calculated_yaw_moment = MainShaftCalculatedYawMomentAPI(client, self._view_id)
- self.torque = MainShaftTorqueAPI(client, self._view_id)
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> MainShaftQueryAPI[MainShaftList]:
- """Query starting at main shafts.
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for main shafts.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(MainShaftList)
- return MainShaftQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- main_shaft: MainShaftWrite | Sequence[MainShaftWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) main shafts.
-
- Args:
- main_shaft: Main shaft or sequence of main shafts to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new main_shaft:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import MainShaftWrite
- >>> client = WindmillClient()
- >>> main_shaft = MainShaftWrite(external_id="my_main_shaft", ...)
- >>> result = client.main_shaft.apply(main_shaft)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.main_shaft.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(main_shaft, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more main shaft.
-
- Args:
- external_id: External id of the main shaft to delete.
- space: The space where all the main shaft are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete main_shaft by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.main_shaft.delete("my_main_shaft")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.main_shaft.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> MainShaft | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> MainShaftList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> MainShaft | MainShaftList | None:
- """Retrieve one or more main shafts by id(s).
-
- Args:
- external_id: External id or list of external ids of the main shafts.
- space: The space where all the main shafts are located.
-
- Returns:
- The requested main shafts.
-
- Examples:
-
- Retrieve main_shaft by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft = client.main_shaft.retrieve("my_main_shaft")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: MainShaftTextFields | SequenceNotStr[MainShaftTextFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: MainShaftFields | SequenceNotStr[MainShaftFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> MainShaftList:
- """Search main shafts
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results main shafts matching the query.
-
- Examples:
-
- Search for 'my_main_shaft' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.search('my_main_shaft')
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: MainShaftFields | SequenceNotStr[MainShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: MainShaftFields | SequenceNotStr[MainShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: MainShaftFields | SequenceNotStr[MainShaftFields],
- property: MainShaftFields | SequenceNotStr[MainShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: MainShaftFields | SequenceNotStr[MainShaftFields] | None = None,
- property: MainShaftFields | SequenceNotStr[MainShaftFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across main shafts
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count main shafts in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.main_shaft.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: MainShaftFields,
- interval: float,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for main shafts
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> MainShaftQuery:
- """Start a query for main shafts."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return MainShaftQuery(self._client)
-
- def select(self) -> MainShaftQuery:
- """Start selecting from main shafts."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return MainShaftQuery(self._client)
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: MainShaftFields | Sequence[MainShaftFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> MainShaftList:
- """List/filter main shafts
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested main shafts
-
- Examples:
-
- List main shafts and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.list(limit=5)
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/main_shaft_bending_x.py b/examples/windmill/_api/main_shaft_bending_x.py
deleted file mode 100644
index 869c363da..000000000
--- a/examples/windmill/_api/main_shaft_bending_x.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._main_shaft import _create_main_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque"]
-
-
-class MainShaftBendingXQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `main_shaft.bending_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_x(external_id="my_bending_x").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `main_shaft.bending_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_x(external_id="my_bending_x").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_x",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `main_shaft.bending_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_x(external_id="my_bending_x").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_x",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `main_shaft.bending_x` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_bending_x' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_x(
- ... external_id="my_bending_x").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "bending_x"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_bending_x(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "bending_x":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MainShaftBendingXAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MainShaftBendingXQuery:
- """Query timeseries `main_shaft.bending_x`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the main_shaft.bending_x timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 main_shaft.bending_x timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.bending_x(limit=5).retrieve()
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return MainShaftBendingXQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `main_shaft.bending_x`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries main_shaft.bending_x.
-
- Examples:
-
- List main_shaft.bending_x and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.bending_x.list(limit=5)
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_bending_x(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_bending_x(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "bending_x",
-) -> dict[str, list[str]]:
- properties = {"bending_x"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("bending_x"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["bending_x"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/main_shaft_bending_y.py b/examples/windmill/_api/main_shaft_bending_y.py
deleted file mode 100644
index c7e8eb1fe..000000000
--- a/examples/windmill/_api/main_shaft_bending_y.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._main_shaft import _create_main_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque"]
-
-
-class MainShaftBendingYQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `main_shaft.bending_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_y(external_id="my_bending_y").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `main_shaft.bending_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_y(external_id="my_bending_y").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_y",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `main_shaft.bending_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_bending_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_y(external_id="my_bending_y").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "bending_y",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `main_shaft.bending_y` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to bending_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_bending_y' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.bending_y(
- ... external_id="my_bending_y").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "bending_y"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_bending_y(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "bending_y":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MainShaftBendingYAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MainShaftBendingYQuery:
- """Query timeseries `main_shaft.bending_y`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the main_shaft.bending_y timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 main_shaft.bending_y timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.bending_y(limit=5).retrieve()
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return MainShaftBendingYQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `main_shaft.bending_y`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries main_shaft.bending_y.
-
- Examples:
-
- List main_shaft.bending_y and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.bending_y.list(limit=5)
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_bending_y(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_bending_y(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "bending_y",
-) -> dict[str, list[str]]:
- properties = {"bending_y"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("bending_y"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["bending_y"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/main_shaft_calculated_tilt_moment.py b/examples/windmill/_api/main_shaft_calculated_tilt_moment.py
deleted file mode 100644
index 72dde6abb..000000000
--- a/examples/windmill/_api/main_shaft_calculated_tilt_moment.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._main_shaft import _create_main_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque"]
-
-
-class MainShaftCalculatedTiltMomentQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `main_shaft.calculated_tilt_moment` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_calculated_tilt_moment' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_tilt_moment(external_id="my_calculated_tilt_moment").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `main_shaft.calculated_tilt_moment` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_calculated_tilt_moment' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_tilt_moment(external_id="my_calculated_tilt_moment").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "calculated_tilt_moment",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `main_shaft.calculated_tilt_moment` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to calculated_tilt_moment
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_calculated_tilt_moment' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_tilt_moment(external_id="my_calculated_tilt_moment").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "calculated_tilt_moment",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `main_shaft.calculated_tilt_moment` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to calculated_tilt_moment
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_calculated_tilt_moment' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_tilt_moment(
- ... external_id="my_calculated_tilt_moment").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "calculated_tilt_moment"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_calculated_tilt_moment(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "calculated_tilt_moment":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MainShaftCalculatedTiltMomentAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MainShaftCalculatedTiltMomentQuery:
- """Query timeseries `main_shaft.calculated_tilt_moment`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the main_shaft.calculated_tilt_moment timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 main_shaft.calculated_tilt_moment timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.calculated_tilt_moment(limit=5).retrieve()
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return MainShaftCalculatedTiltMomentQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `main_shaft.calculated_tilt_moment`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries main_shaft.calculated_tilt_moment.
-
- Examples:
-
- List main_shaft.calculated_tilt_moment and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.calculated_tilt_moment.list(limit=5)
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_calculated_tilt_moment(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_calculated_tilt_moment(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "calculated_tilt_moment",
-) -> dict[str, list[str]]:
- properties = {"calculated_tilt_moment"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("calculated_tilt_moment"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["calculated_tilt_moment"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/main_shaft_calculated_yaw_moment.py b/examples/windmill/_api/main_shaft_calculated_yaw_moment.py
deleted file mode 100644
index b6df6d482..000000000
--- a/examples/windmill/_api/main_shaft_calculated_yaw_moment.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._main_shaft import _create_main_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque"]
-
-
-class MainShaftCalculatedYawMomentQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `main_shaft.calculated_yaw_moment` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_calculated_yaw_moment' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_yaw_moment(external_id="my_calculated_yaw_moment").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `main_shaft.calculated_yaw_moment` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_calculated_yaw_moment' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_yaw_moment(external_id="my_calculated_yaw_moment").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "calculated_yaw_moment",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `main_shaft.calculated_yaw_moment` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to calculated_yaw_moment
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_calculated_yaw_moment' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_yaw_moment(external_id="my_calculated_yaw_moment").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "calculated_yaw_moment",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `main_shaft.calculated_yaw_moment` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to calculated_yaw_moment
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_calculated_yaw_moment' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.calculated_yaw_moment(
- ... external_id="my_calculated_yaw_moment").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "calculated_yaw_moment"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_calculated_yaw_moment(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "calculated_yaw_moment":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MainShaftCalculatedYawMomentAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MainShaftCalculatedYawMomentQuery:
- """Query timeseries `main_shaft.calculated_yaw_moment`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the main_shaft.calculated_yaw_moment timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 main_shaft.calculated_yaw_moment timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.calculated_yaw_moment(limit=5).retrieve()
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return MainShaftCalculatedYawMomentQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `main_shaft.calculated_yaw_moment`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries main_shaft.calculated_yaw_moment.
-
- Examples:
-
- List main_shaft.calculated_yaw_moment and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.calculated_yaw_moment.list(limit=5)
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_calculated_yaw_moment(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_calculated_yaw_moment(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "calculated_yaw_moment",
-) -> dict[str, list[str]]:
- properties = {"calculated_yaw_moment"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("calculated_yaw_moment"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["calculated_yaw_moment"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/main_shaft_query.py b/examples/windmill/_api/main_shaft_query.py
deleted file mode 100644
index e952407fe..000000000
--- a/examples/windmill/_api/main_shaft_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- MainShaft,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class MainShaftQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "MainShaft", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=MainShaft,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/main_shaft_torque.py b/examples/windmill/_api/main_shaft_torque.py
deleted file mode 100644
index 30e400eb3..000000000
--- a/examples/windmill/_api/main_shaft_torque.py
+++ /dev/null
@@ -1,491 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._main_shaft import _create_main_shaft_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque"]
-
-
-class MainShaftTorqueQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `main_shaft.torque` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_torque' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.torque(external_id="my_torque").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `main_shaft.torque` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_torque' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.torque(external_id="my_torque").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "torque",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `main_shaft.torque` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to torque
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_torque' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.torque(external_id="my_torque").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "torque",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `main_shaft.torque` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to torque
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_torque' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> main_shaft_datapoints = client.main_shaft.torque(
- ... external_id="my_torque").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "torque"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_torque(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "torque":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MainShaftTorqueAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MainShaftTorqueQuery:
- """Query timeseries `main_shaft.torque`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the main_shaft.torque timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 main_shaft.torque timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.torque(limit=5).retrieve()
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return MainShaftTorqueQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `main_shaft.torque`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of main shafts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries main_shaft.torque.
-
- Examples:
-
- List main_shaft.torque and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> main_shafts = client.main_shaft.torque.list(limit=5)
-
- """
- filter_ = _create_main_shaft_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_torque(self._client, self._view_id, filter_, limit)
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_torque(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "torque",
-) -> dict[str, list[str]]:
- properties = {"torque"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("torque"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["torque"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/metmast.py b/examples/windmill/_api/metmast.py
deleted file mode 100644
index bbd9c2d97..000000000
--- a/examples/windmill/_api/metmast.py
+++ /dev/null
@@ -1,482 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Metmast,
- MetmastWrite,
- MetmastFields,
- MetmastList,
- MetmastWriteList,
- MetmastTextFields,
-)
-from windmill.data_classes._metmast import (
- MetmastQuery,
- _METMAST_PROPERTIES_BY_FIELD,
- _create_metmast_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.metmast_temperature import MetmastTemperatureAPI
-from windmill._api.metmast_tilt_angle import MetmastTiltAngleAPI
-from windmill._api.metmast_wind_speed import MetmastWindSpeedAPI
-from windmill._api.metmast_query import MetmastQueryAPI
-
-
-class MetmastAPI(NodeAPI[Metmast, MetmastWrite, MetmastList, MetmastWriteList]):
- _view_id = dm.ViewId("power-models", "Metmast", "1")
- _properties_by_field = _METMAST_PROPERTIES_BY_FIELD
- _class_type = Metmast
- _class_list = MetmastList
- _class_write_list = MetmastWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.temperature = MetmastTemperatureAPI(client, self._view_id)
- self.tilt_angle = MetmastTiltAngleAPI(client, self._view_id)
- self.wind_speed = MetmastWindSpeedAPI(client, self._view_id)
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> MetmastQueryAPI[MetmastList]:
- """Query starting at metmasts.
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for metmasts.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(MetmastList)
- return MetmastQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- metmast: MetmastWrite | Sequence[MetmastWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) metmasts.
-
- Args:
- metmast: Metmast or sequence of metmasts to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new metmast:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import MetmastWrite
- >>> client = WindmillClient()
- >>> metmast = MetmastWrite(external_id="my_metmast", ...)
- >>> result = client.metmast.apply(metmast)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.metmast.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(metmast, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more metmast.
-
- Args:
- external_id: External id of the metmast to delete.
- space: The space where all the metmast are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete metmast by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.metmast.delete("my_metmast")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.metmast.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Metmast | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> MetmastList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Metmast | MetmastList | None:
- """Retrieve one or more metmasts by id(s).
-
- Args:
- external_id: External id or list of external ids of the metmasts.
- space: The space where all the metmasts are located.
-
- Returns:
- The requested metmasts.
-
- Examples:
-
- Retrieve metmast by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast = client.metmast.retrieve("my_metmast")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: MetmastTextFields | SequenceNotStr[MetmastTextFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: MetmastFields | SequenceNotStr[MetmastFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> MetmastList:
- """Search metmasts
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results metmasts matching the query.
-
- Examples:
-
- Search for 'my_metmast' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.search('my_metmast')
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: MetmastFields | SequenceNotStr[MetmastFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: MetmastFields | SequenceNotStr[MetmastFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: MetmastFields | SequenceNotStr[MetmastFields],
- property: MetmastFields | SequenceNotStr[MetmastFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: MetmastFields | SequenceNotStr[MetmastFields] | None = None,
- property: MetmastFields | SequenceNotStr[MetmastFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across metmasts
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count metmasts in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.metmast.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: MetmastFields,
- interval: float,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for metmasts
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> MetmastQuery:
- """Start a query for metmasts."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return MetmastQuery(self._client)
-
- def select(self) -> MetmastQuery:
- """Start selecting from metmasts."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return MetmastQuery(self._client)
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: MetmastFields | Sequence[MetmastFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> MetmastList:
- """List/filter metmasts
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested metmasts
-
- Examples:
-
- List metmasts and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.list(limit=5)
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/metmast_query.py b/examples/windmill/_api/metmast_query.py
deleted file mode 100644
index 58e5c704a..000000000
--- a/examples/windmill/_api/metmast_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Metmast,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class MetmastQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Metmast", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Metmast,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/metmast_temperature.py b/examples/windmill/_api/metmast_temperature.py
deleted file mode 100644
index c68dffc64..000000000
--- a/examples/windmill/_api/metmast_temperature.py
+++ /dev/null
@@ -1,505 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._metmast import _create_metmast_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["position", "temperature", "tilt_angle", "wind_speed"]
-
-
-class MetmastTemperatureQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `metmast.temperature` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_temperature' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.temperature(external_id="my_temperature").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `metmast.temperature` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_temperature' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.temperature(external_id="my_temperature").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "temperature",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `metmast.temperature` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to temperature
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_temperature' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.temperature(external_id="my_temperature").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "temperature",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `metmast.temperature` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to temperature
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_temperature' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.temperature(
- ... external_id="my_temperature").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "temperature"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_temperature(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "temperature":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MetmastTemperatureAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MetmastTemperatureQuery:
- """Query timeseries `metmast.temperature`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the metmast.temperature timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 metmast.temperature timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.temperature(limit=5).retrieve()
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return MetmastTemperatureQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `metmast.temperature`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries metmast.temperature.
-
- Examples:
-
- List metmast.temperature and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.temperature.list(limit=5)
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_temperature(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_temperature(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "temperature",
-) -> dict[str, list[str]]:
- properties = {"temperature"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("temperature"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["temperature"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/metmast_tilt_angle.py b/examples/windmill/_api/metmast_tilt_angle.py
deleted file mode 100644
index ca6af338d..000000000
--- a/examples/windmill/_api/metmast_tilt_angle.py
+++ /dev/null
@@ -1,505 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._metmast import _create_metmast_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["position", "temperature", "tilt_angle", "wind_speed"]
-
-
-class MetmastTiltAngleQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `metmast.tilt_angle` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_tilt_angle' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.tilt_angle(external_id="my_tilt_angle").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `metmast.tilt_angle` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_tilt_angle' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.tilt_angle(external_id="my_tilt_angle").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "tilt_angle",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `metmast.tilt_angle` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to tilt_angle
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_tilt_angle' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.tilt_angle(external_id="my_tilt_angle").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "tilt_angle",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `metmast.tilt_angle` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to tilt_angle
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_tilt_angle' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.tilt_angle(
- ... external_id="my_tilt_angle").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "tilt_angle"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_tilt_angle(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "tilt_angle":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MetmastTiltAngleAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MetmastTiltAngleQuery:
- """Query timeseries `metmast.tilt_angle`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the metmast.tilt_angle timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 metmast.tilt_angle timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.tilt_angle(limit=5).retrieve()
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return MetmastTiltAngleQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `metmast.tilt_angle`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries metmast.tilt_angle.
-
- Examples:
-
- List metmast.tilt_angle and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.tilt_angle.list(limit=5)
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_tilt_angle(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_tilt_angle(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "tilt_angle",
-) -> dict[str, list[str]]:
- properties = {"tilt_angle"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("tilt_angle"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["tilt_angle"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/metmast_wind_speed.py b/examples/windmill/_api/metmast_wind_speed.py
deleted file mode 100644
index 35ece3459..000000000
--- a/examples/windmill/_api/metmast_wind_speed.py
+++ /dev/null
@@ -1,505 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._metmast import _create_metmast_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["position", "temperature", "tilt_angle", "wind_speed"]
-
-
-class MetmastWindSpeedQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `metmast.wind_speed` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_wind_speed' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.wind_speed(external_id="my_wind_speed").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `metmast.wind_speed` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_wind_speed' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.wind_speed(external_id="my_wind_speed").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "wind_speed",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `metmast.wind_speed` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to wind_speed
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_wind_speed' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.wind_speed(external_id="my_wind_speed").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "wind_speed",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `metmast.wind_speed` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to wind_speed
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_wind_speed' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> metmast_datapoints = client.metmast.wind_speed(
- ... external_id="my_wind_speed").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "wind_speed"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_wind_speed(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "wind_speed":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class MetmastWindSpeedAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> MetmastWindSpeedQuery:
- """Query timeseries `metmast.wind_speed`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the metmast.wind_speed timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 metmast.wind_speed timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.wind_speed(limit=5).retrieve()
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return MetmastWindSpeedQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `metmast.wind_speed`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmasts to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries metmast.wind_speed.
-
- Examples:
-
- List metmast.wind_speed and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> metmasts = client.metmast.wind_speed.list(limit=5)
-
- """
- filter_ = _create_metmast_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_wind_speed(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_wind_speed(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "wind_speed",
-) -> dict[str, list[str]]:
- properties = {"wind_speed"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("wind_speed"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["wind_speed"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/nacelle.py b/examples/windmill/_api/nacelle.py
deleted file mode 100644
index f403a97fb..000000000
--- a/examples/windmill/_api/nacelle.py
+++ /dev/null
@@ -1,913 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Nacelle,
- NacelleWrite,
- NacelleFields,
- NacelleList,
- NacelleWriteList,
- NacelleTextFields,
- Gearbox,
- Generator,
- HighSpeedShaft,
- MainShaft,
- PowerInverter,
-)
-from windmill.data_classes._nacelle import (
- NacelleQuery,
- _NACELLE_PROPERTIES_BY_FIELD,
- _create_nacelle_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.nacelle_acc_from_back_side_x import NacelleAccFromBackSideXAPI
-from windmill._api.nacelle_acc_from_back_side_y import NacelleAccFromBackSideYAPI
-from windmill._api.nacelle_acc_from_back_side_z import NacelleAccFromBackSideZAPI
-from windmill._api.nacelle_yaw_direction import NacelleYawDirectionAPI
-from windmill._api.nacelle_yaw_error import NacelleYawErrorAPI
-from windmill._api.nacelle_query import NacelleQueryAPI
-
-
-class NacelleAPI(NodeAPI[Nacelle, NacelleWrite, NacelleList, NacelleWriteList]):
- _view_id = dm.ViewId("power-models", "Nacelle", "1")
- _properties_by_field = _NACELLE_PROPERTIES_BY_FIELD
- _class_type = Nacelle
- _class_list = NacelleList
- _class_write_list = NacelleWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.acc_from_back_side_x = NacelleAccFromBackSideXAPI(client, self._view_id)
- self.acc_from_back_side_y = NacelleAccFromBackSideYAPI(client, self._view_id)
- self.acc_from_back_side_z = NacelleAccFromBackSideZAPI(client, self._view_id)
- self.yaw_direction = NacelleYawDirectionAPI(client, self._view_id)
- self.yaw_error = NacelleYawErrorAPI(client, self._view_id)
-
- def __call__(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> NacelleQueryAPI[NacelleList]:
- """Query starting at nacelles.
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for nacelles.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(NacelleList)
- return NacelleQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- nacelle: NacelleWrite | Sequence[NacelleWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) nacelles.
-
- Note: This method iterates through all nodes and timeseries linked to nacelle and creates them including the edges
- between the nodes. For example, if any of `gearbox`, `generator`, `high_speed_shaft`, `main_shaft` or `power_inverter` are set, then these
- nodes as well as any nodes linked to them, and all the edges linking these nodes will be created.
-
- Args:
- nacelle: Nacelle or sequence of nacelles to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new nacelle:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import NacelleWrite
- >>> client = WindmillClient()
- >>> nacelle = NacelleWrite(external_id="my_nacelle", ...)
- >>> result = client.nacelle.apply(nacelle)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.nacelle.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(nacelle, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more nacelle.
-
- Args:
- external_id: External id of the nacelle to delete.
- space: The space where all the nacelle are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete nacelle by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.nacelle.delete("my_nacelle")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.nacelle.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Nacelle | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> NacelleList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Nacelle | NacelleList | None:
- """Retrieve one or more nacelles by id(s).
-
- Args:
- external_id: External id or list of external ids of the nacelles.
- space: The space where all the nacelles are located.
-
- Returns:
- The requested nacelles.
-
- Examples:
-
- Retrieve nacelle by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle = client.nacelle.retrieve("my_nacelle")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: NacelleTextFields | SequenceNotStr[NacelleTextFields] | None = None,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: NacelleFields | SequenceNotStr[NacelleFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> NacelleList:
- """Search nacelles
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results nacelles matching the query.
-
- Examples:
-
- Search for 'my_nacelle' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.search('my_nacelle')
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: NacelleFields | SequenceNotStr[NacelleFields] | None = None,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: NacelleFields | SequenceNotStr[NacelleFields] | None = None,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: NacelleFields | SequenceNotStr[NacelleFields],
- property: NacelleFields | SequenceNotStr[NacelleFields] | None = None,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: NacelleFields | SequenceNotStr[NacelleFields] | None = None,
- property: NacelleFields | SequenceNotStr[NacelleFields] | None = None,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across nacelles
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count nacelles in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.nacelle.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: NacelleFields,
- interval: float,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for nacelles
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> NacelleQuery:
- """Start a query for nacelles."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return NacelleQuery(self._client)
-
- def select(self) -> NacelleQuery:
- """Start selecting from nacelles."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return NacelleQuery(self._client)
-
- def list(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: NacelleFields | Sequence[NacelleFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- retrieve_connections: Literal["skip", "identifier", "full"] = "skip",
- ) -> NacelleList:
- """List/filter nacelles
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
- retrieve_connections: Whether to retrieve `gearbox`, `generator`, `high_speed_shaft`, `main_shaft` and `power_inverter` for the nacelles. Defaults to 'skip'.
- 'skip' will not retrieve any connections, 'identifier' will only retrieve the identifier of the connected items, and 'full' will retrieve the full connected items.
-
- Returns:
- List of requested nacelles
-
- Examples:
-
- List nacelles and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.list(limit=5)
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
-
- if retrieve_connections == "skip":
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- builder = DataClassQueryBuilder(NacelleList)
- has_data = dm.filters.HasData(views=[self._view_id])
- builder.append(
- NodeQueryStep(
- builder.create_name(None),
- dm.query.NodeResultSetExpression(
- filter=dm.filters.And(filter_, has_data) if filter_ else has_data,
- sort=self._create_sort(sort_by, direction, sort), # type: ignore[arg-type]
- ),
- Nacelle,
- max_retrieve_limit=limit,
- raw_filter=filter_,
- )
- )
- from_root = builder.get_from()
- if retrieve_connections == "full":
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[Gearbox._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("gearbox"),
- ),
- Gearbox,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[Generator._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("generator"),
- ),
- Generator,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[HighSpeedShaft._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("high_speed_shaft"),
- ),
- HighSpeedShaft,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[MainShaft._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("main_shaft"),
- ),
- MainShaft,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[PowerInverter._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("power_inverter"),
- ),
- PowerInverter,
- )
- )
- # We know that that all nodes are connected as it is not possible to filter on connections
- builder.execute_query(self._client, remove_not_connected=False)
- return builder.unpack()
diff --git a/examples/windmill/_api/nacelle_acc_from_back_side_x.py b/examples/windmill/_api/nacelle_acc_from_back_side_x.py
deleted file mode 100644
index 8edbe95e3..000000000
--- a/examples/windmill/_api/nacelle_acc_from_back_side_x.py
+++ /dev/null
@@ -1,595 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._nacelle import _create_nacelle_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error"
-]
-
-
-class NacelleAccFromBackSideXQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `nacelle.acc_from_back_side_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_x(external_id="my_acc_from_back_side_x").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `nacelle.acc_from_back_side_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_x(external_id="my_acc_from_back_side_x").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "acc_from_back_side_x",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `nacelle.acc_from_back_side_x` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to acc_from_back_side_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_x' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_x(external_id="my_acc_from_back_side_x").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "acc_from_back_side_x",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `nacelle.acc_from_back_side_x` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to acc_from_back_side_x
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_acc_from_back_side_x' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_x(
- ... external_id="my_acc_from_back_side_x").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "acc_from_back_side_x"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_x(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "acc_from_back_side_x":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class NacelleAccFromBackSideXAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> NacelleAccFromBackSideXQuery:
- """Query timeseries `nacelle.acc_from_back_side_x`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the nacelle.acc_from_back_side_x timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 nacelle.acc_from_back_side_x timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.acc_from_back_side_x(limit=5).retrieve()
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
-
- return NacelleAccFromBackSideXQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `nacelle.acc_from_back_side_x`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries nacelle.acc_from_back_side_x.
-
- Examples:
-
- List nacelle.acc_from_back_side_x and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.acc_from_back_side_x.list(limit=5)
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_x(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_x(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "acc_from_back_side_x",
-) -> dict[str, list[str]]:
- properties = {"acc_from_back_side_x"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("acc_from_back_side_x"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["acc_from_back_side_x"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/nacelle_acc_from_back_side_y.py b/examples/windmill/_api/nacelle_acc_from_back_side_y.py
deleted file mode 100644
index e9b393b9b..000000000
--- a/examples/windmill/_api/nacelle_acc_from_back_side_y.py
+++ /dev/null
@@ -1,595 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._nacelle import _create_nacelle_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error"
-]
-
-
-class NacelleAccFromBackSideYQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `nacelle.acc_from_back_side_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_y(external_id="my_acc_from_back_side_y").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `nacelle.acc_from_back_side_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_y(external_id="my_acc_from_back_side_y").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "acc_from_back_side_y",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `nacelle.acc_from_back_side_y` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to acc_from_back_side_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_y' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_y(external_id="my_acc_from_back_side_y").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "acc_from_back_side_y",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `nacelle.acc_from_back_side_y` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to acc_from_back_side_y
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_acc_from_back_side_y' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_y(
- ... external_id="my_acc_from_back_side_y").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "acc_from_back_side_y"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_y(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "acc_from_back_side_y":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class NacelleAccFromBackSideYAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> NacelleAccFromBackSideYQuery:
- """Query timeseries `nacelle.acc_from_back_side_y`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the nacelle.acc_from_back_side_y timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 nacelle.acc_from_back_side_y timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.acc_from_back_side_y(limit=5).retrieve()
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
-
- return NacelleAccFromBackSideYQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `nacelle.acc_from_back_side_y`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries nacelle.acc_from_back_side_y.
-
- Examples:
-
- List nacelle.acc_from_back_side_y and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.acc_from_back_side_y.list(limit=5)
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_y(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_y(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "acc_from_back_side_y",
-) -> dict[str, list[str]]:
- properties = {"acc_from_back_side_y"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("acc_from_back_side_y"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["acc_from_back_side_y"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/nacelle_acc_from_back_side_z.py b/examples/windmill/_api/nacelle_acc_from_back_side_z.py
deleted file mode 100644
index 49cc5c46c..000000000
--- a/examples/windmill/_api/nacelle_acc_from_back_side_z.py
+++ /dev/null
@@ -1,595 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._nacelle import _create_nacelle_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error"
-]
-
-
-class NacelleAccFromBackSideZQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `nacelle.acc_from_back_side_z` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_z' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_z(external_id="my_acc_from_back_side_z").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `nacelle.acc_from_back_side_z` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_z' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_z(external_id="my_acc_from_back_side_z").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "acc_from_back_side_z",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `nacelle.acc_from_back_side_z` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to acc_from_back_side_z
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_acc_from_back_side_z' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_z(external_id="my_acc_from_back_side_z").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "acc_from_back_side_z",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `nacelle.acc_from_back_side_z` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to acc_from_back_side_z
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_acc_from_back_side_z' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.acc_from_back_side_z(
- ... external_id="my_acc_from_back_side_z").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "acc_from_back_side_z"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_z(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "acc_from_back_side_z":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class NacelleAccFromBackSideZAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> NacelleAccFromBackSideZQuery:
- """Query timeseries `nacelle.acc_from_back_side_z`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the nacelle.acc_from_back_side_z timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 nacelle.acc_from_back_side_z timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.acc_from_back_side_z(limit=5).retrieve()
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
-
- return NacelleAccFromBackSideZQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `nacelle.acc_from_back_side_z`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries nacelle.acc_from_back_side_z.
-
- Examples:
-
- List nacelle.acc_from_back_side_z and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.acc_from_back_side_z.list(limit=5)
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_z(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_acc_from_back_side_z(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "acc_from_back_side_z",
-) -> dict[str, list[str]]:
- properties = {"acc_from_back_side_z"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("acc_from_back_side_z"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["acc_from_back_side_z"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/nacelle_query.py b/examples/windmill/_api/nacelle_query.py
deleted file mode 100644
index 09e49d26a..000000000
--- a/examples/windmill/_api/nacelle_query.py
+++ /dev/null
@@ -1,155 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Nacelle,
- Gearbox,
- Generator,
- HighSpeedShaft,
- MainShaft,
- PowerInverter,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class NacelleQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Nacelle", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Nacelle,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- retrieve_gearbox: bool = False,
- retrieve_generator: bool = False,
- retrieve_high_speed_shaft: bool = False,
- retrieve_main_shaft: bool = False,
- retrieve_power_inverter: bool = False,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Args:
- retrieve_gearbox: Whether to retrieve the gearbox for each nacelle or not.
- retrieve_generator: Whether to retrieve the generator for each nacelle or not.
- retrieve_high_speed_shaft: Whether to retrieve the high speed shaft for each nacelle or not.
- retrieve_main_shaft: Whether to retrieve the main shaft for each nacelle or not.
- retrieve_power_inverter: Whether to retrieve the power inverter for each nacelle or not.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- from_ = self._builder[-1].name
- if retrieve_gearbox:
- self._query_append_gearbox(from_)
- if retrieve_generator:
- self._query_append_generator(from_)
- if retrieve_high_speed_shaft:
- self._query_append_high_speed_shaft(from_)
- if retrieve_main_shaft:
- self._query_append_main_shaft(from_)
- if retrieve_power_inverter:
- self._query_append_power_inverter(from_)
- return self._query()
-
- def _query_append_gearbox(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("gearbox"),
- direction="outwards",
- filter=dm.filters.HasData(views=[Gearbox._view_id]),
- ),
- result_cls=Gearbox,
- ),
- )
-
- def _query_append_generator(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("generator"),
- direction="outwards",
- filter=dm.filters.HasData(views=[Generator._view_id]),
- ),
- result_cls=Generator,
- ),
- )
-
- def _query_append_high_speed_shaft(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("high_speed_shaft"),
- direction="outwards",
- filter=dm.filters.HasData(views=[HighSpeedShaft._view_id]),
- ),
- result_cls=HighSpeedShaft,
- ),
- )
-
- def _query_append_main_shaft(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("main_shaft"),
- direction="outwards",
- filter=dm.filters.HasData(views=[MainShaft._view_id]),
- ),
- result_cls=MainShaft,
- ),
- )
-
- def _query_append_power_inverter(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("power_inverter"),
- direction="outwards",
- filter=dm.filters.HasData(views=[PowerInverter._view_id]),
- ),
- result_cls=PowerInverter,
- ),
- )
diff --git a/examples/windmill/_api/nacelle_yaw_direction.py b/examples/windmill/_api/nacelle_yaw_direction.py
deleted file mode 100644
index fe7d8423b..000000000
--- a/examples/windmill/_api/nacelle_yaw_direction.py
+++ /dev/null
@@ -1,595 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._nacelle import _create_nacelle_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error"
-]
-
-
-class NacelleYawDirectionQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `nacelle.yaw_direction` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_yaw_direction' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_direction(external_id="my_yaw_direction").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `nacelle.yaw_direction` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_yaw_direction' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_direction(external_id="my_yaw_direction").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "yaw_direction",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `nacelle.yaw_direction` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to yaw_direction
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_yaw_direction' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_direction(external_id="my_yaw_direction").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "yaw_direction",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `nacelle.yaw_direction` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to yaw_direction
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_yaw_direction' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_direction(
- ... external_id="my_yaw_direction").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "yaw_direction"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_yaw_direction(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "yaw_direction":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class NacelleYawDirectionAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> NacelleYawDirectionQuery:
- """Query timeseries `nacelle.yaw_direction`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the nacelle.yaw_direction timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 nacelle.yaw_direction timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.yaw_direction(limit=5).retrieve()
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
-
- return NacelleYawDirectionQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `nacelle.yaw_direction`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries nacelle.yaw_direction.
-
- Examples:
-
- List nacelle.yaw_direction and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.yaw_direction.list(limit=5)
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_yaw_direction(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_yaw_direction(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "yaw_direction",
-) -> dict[str, list[str]]:
- properties = {"yaw_direction"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("yaw_direction"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["yaw_direction"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/nacelle_yaw_error.py b/examples/windmill/_api/nacelle_yaw_error.py
deleted file mode 100644
index 09d021345..000000000
--- a/examples/windmill/_api/nacelle_yaw_error.py
+++ /dev/null
@@ -1,595 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._nacelle import _create_nacelle_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error"
-]
-
-
-class NacelleYawErrorQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `nacelle.yaw_error` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_yaw_error' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_error(external_id="my_yaw_error").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `nacelle.yaw_error` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_yaw_error' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_error(external_id="my_yaw_error").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "yaw_error",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `nacelle.yaw_error` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to yaw_error
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_yaw_error' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_error(external_id="my_yaw_error").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "yaw_error",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `nacelle.yaw_error` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to yaw_error
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_yaw_error' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> nacelle_datapoints = client.nacelle.yaw_error(
- ... external_id="my_yaw_error").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "yaw_error"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_yaw_error(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "yaw_error":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class NacelleYawErrorAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> NacelleYawErrorQuery:
- """Query timeseries `nacelle.yaw_error`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the nacelle.yaw_error timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 nacelle.yaw_error timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.yaw_error(limit=5).retrieve()
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
-
- return NacelleYawErrorQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- gearbox: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- generator: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- high_speed_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- main_shaft: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- power_inverter: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `nacelle.yaw_error`
-
- Args:
- gearbox: The gearbox to filter on.
- generator: The generator to filter on.
- high_speed_shaft: The high speed shaft to filter on.
- main_shaft: The main shaft to filter on.
- power_inverter: The power inverter to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of nacelles to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries nacelle.yaw_error.
-
- Examples:
-
- List nacelle.yaw_error and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> nacelles = client.nacelle.yaw_error.list(limit=5)
-
- """
- filter_ = _create_nacelle_filter(
- self._view_id,
- gearbox,
- generator,
- high_speed_shaft,
- main_shaft,
- power_inverter,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_yaw_error(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_yaw_error(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "yaw_error",
-) -> dict[str, list[str]]:
- properties = {"yaw_error"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("yaw_error"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["yaw_error"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/power_inverter.py b/examples/windmill/_api/power_inverter.py
deleted file mode 100644
index 19096b979..000000000
--- a/examples/windmill/_api/power_inverter.py
+++ /dev/null
@@ -1,446 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- PowerInverter,
- PowerInverterWrite,
- PowerInverterFields,
- PowerInverterList,
- PowerInverterWriteList,
- PowerInverterTextFields,
-)
-from windmill.data_classes._power_inverter import (
- PowerInverterQuery,
- _POWERINVERTER_PROPERTIES_BY_FIELD,
- _create_power_inverter_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.power_inverter_active_power_total import PowerInverterActivePowerTotalAPI
-from windmill._api.power_inverter_apparent_power_total import PowerInverterApparentPowerTotalAPI
-from windmill._api.power_inverter_reactive_power_total import PowerInverterReactivePowerTotalAPI
-from windmill._api.power_inverter_query import PowerInverterQueryAPI
-
-
-class PowerInverterAPI(NodeAPI[PowerInverter, PowerInverterWrite, PowerInverterList, PowerInverterWriteList]):
- _view_id = dm.ViewId("power-models", "PowerInverter", "1")
- _properties_by_field = _POWERINVERTER_PROPERTIES_BY_FIELD
- _class_type = PowerInverter
- _class_list = PowerInverterList
- _class_write_list = PowerInverterWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.active_power_total = PowerInverterActivePowerTotalAPI(client, self._view_id)
- self.apparent_power_total = PowerInverterApparentPowerTotalAPI(client, self._view_id)
- self.reactive_power_total = PowerInverterReactivePowerTotalAPI(client, self._view_id)
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> PowerInverterQueryAPI[PowerInverterList]:
- """Query starting at power inverters.
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for power inverters.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(PowerInverterList)
- return PowerInverterQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- power_inverter: PowerInverterWrite | Sequence[PowerInverterWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) power inverters.
-
- Args:
- power_inverter: Power inverter or sequence of power inverters to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new power_inverter:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import PowerInverterWrite
- >>> client = WindmillClient()
- >>> power_inverter = PowerInverterWrite(external_id="my_power_inverter", ...)
- >>> result = client.power_inverter.apply(power_inverter)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.power_inverter.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(power_inverter, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more power inverter.
-
- Args:
- external_id: External id of the power inverter to delete.
- space: The space where all the power inverter are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete power_inverter by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.power_inverter.delete("my_power_inverter")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.power_inverter.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> PowerInverter | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> PowerInverterList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> PowerInverter | PowerInverterList | None:
- """Retrieve one or more power inverters by id(s).
-
- Args:
- external_id: External id or list of external ids of the power inverters.
- space: The space where all the power inverters are located.
-
- Returns:
- The requested power inverters.
-
- Examples:
-
- Retrieve power_inverter by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter = client.power_inverter.retrieve("my_power_inverter")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: PowerInverterTextFields | SequenceNotStr[PowerInverterTextFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: PowerInverterFields | SequenceNotStr[PowerInverterFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> PowerInverterList:
- """Search power inverters
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results power inverters matching the query.
-
- Examples:
-
- Search for 'my_power_inverter' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.search('my_power_inverter')
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: PowerInverterFields | SequenceNotStr[PowerInverterFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: PowerInverterFields | SequenceNotStr[PowerInverterFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: PowerInverterFields | SequenceNotStr[PowerInverterFields],
- property: PowerInverterFields | SequenceNotStr[PowerInverterFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: PowerInverterFields | SequenceNotStr[PowerInverterFields] | None = None,
- property: PowerInverterFields | SequenceNotStr[PowerInverterFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across power inverters
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count power inverters in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.power_inverter.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: PowerInverterFields,
- interval: float,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for power inverters
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> PowerInverterQuery:
- """Start a query for power inverters."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return PowerInverterQuery(self._client)
-
- def select(self) -> PowerInverterQuery:
- """Start selecting from power inverters."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return PowerInverterQuery(self._client)
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: PowerInverterFields | Sequence[PowerInverterFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> PowerInverterList:
- """List/filter power inverters
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested power inverters
-
- Examples:
-
- List power inverters and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.list(limit=5)
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/power_inverter_active_power_total.py b/examples/windmill/_api/power_inverter_active_power_total.py
deleted file mode 100644
index 90ecd9886..000000000
--- a/examples/windmill/_api/power_inverter_active_power_total.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._power_inverter import _create_power_inverter_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["active_power_total", "apparent_power_total", "reactive_power_total"]
-
-
-class PowerInverterActivePowerTotalQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `power_inverter.active_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_active_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.active_power_total(external_id="my_active_power_total").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `power_inverter.active_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_active_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.active_power_total(external_id="my_active_power_total").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "active_power_total",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `power_inverter.active_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to active_power_total
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_active_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.active_power_total(external_id="my_active_power_total").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "active_power_total",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `power_inverter.active_power_total` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to active_power_total
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_active_power_total' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.active_power_total(
- ... external_id="my_active_power_total").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "active_power_total"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_active_power_total(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "active_power_total":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class PowerInverterActivePowerTotalAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> PowerInverterActivePowerTotalQuery:
- """Query timeseries `power_inverter.active_power_total`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the power_inverter.active_power_total timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 power_inverter.active_power_total timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.active_power_total(limit=5).retrieve()
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return PowerInverterActivePowerTotalQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `power_inverter.active_power_total`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries power_inverter.active_power_total.
-
- Examples:
-
- List power_inverter.active_power_total and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.active_power_total.list(limit=5)
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_active_power_total(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_active_power_total(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "active_power_total",
-) -> dict[str, list[str]]:
- properties = {"active_power_total"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("active_power_total"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["active_power_total"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/power_inverter_apparent_power_total.py b/examples/windmill/_api/power_inverter_apparent_power_total.py
deleted file mode 100644
index b6cfbdd20..000000000
--- a/examples/windmill/_api/power_inverter_apparent_power_total.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._power_inverter import _create_power_inverter_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["active_power_total", "apparent_power_total", "reactive_power_total"]
-
-
-class PowerInverterApparentPowerTotalQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `power_inverter.apparent_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_apparent_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.apparent_power_total(external_id="my_apparent_power_total").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `power_inverter.apparent_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_apparent_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.apparent_power_total(external_id="my_apparent_power_total").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "apparent_power_total",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `power_inverter.apparent_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to apparent_power_total
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_apparent_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.apparent_power_total(external_id="my_apparent_power_total").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "apparent_power_total",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `power_inverter.apparent_power_total` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to apparent_power_total
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_apparent_power_total' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.apparent_power_total(
- ... external_id="my_apparent_power_total").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "apparent_power_total"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_apparent_power_total(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "apparent_power_total":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class PowerInverterApparentPowerTotalAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> PowerInverterApparentPowerTotalQuery:
- """Query timeseries `power_inverter.apparent_power_total`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the power_inverter.apparent_power_total timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 power_inverter.apparent_power_total timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.apparent_power_total(limit=5).retrieve()
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return PowerInverterApparentPowerTotalQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `power_inverter.apparent_power_total`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries power_inverter.apparent_power_total.
-
- Examples:
-
- List power_inverter.apparent_power_total and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.apparent_power_total.list(limit=5)
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_apparent_power_total(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_apparent_power_total(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "apparent_power_total",
-) -> dict[str, list[str]]:
- properties = {"apparent_power_total"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("apparent_power_total"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["apparent_power_total"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/power_inverter_query.py b/examples/windmill/_api/power_inverter_query.py
deleted file mode 100644
index 64a9b2b52..000000000
--- a/examples/windmill/_api/power_inverter_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- PowerInverter,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class PowerInverterQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "PowerInverter", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=PowerInverter,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/power_inverter_reactive_power_total.py b/examples/windmill/_api/power_inverter_reactive_power_total.py
deleted file mode 100644
index 4e6eaf1f5..000000000
--- a/examples/windmill/_api/power_inverter_reactive_power_total.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._power_inverter import _create_power_inverter_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["active_power_total", "apparent_power_total", "reactive_power_total"]
-
-
-class PowerInverterReactivePowerTotalQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `power_inverter.reactive_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_reactive_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.reactive_power_total(external_id="my_reactive_power_total").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `power_inverter.reactive_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_reactive_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.reactive_power_total(external_id="my_reactive_power_total").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "reactive_power_total",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `power_inverter.reactive_power_total` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to reactive_power_total
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_reactive_power_total' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.reactive_power_total(external_id="my_reactive_power_total").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "reactive_power_total",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `power_inverter.reactive_power_total` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to reactive_power_total
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_reactive_power_total' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> power_inverter_datapoints = client.power_inverter.reactive_power_total(
- ... external_id="my_reactive_power_total").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "reactive_power_total"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_reactive_power_total(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "reactive_power_total":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class PowerInverterReactivePowerTotalAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> PowerInverterReactivePowerTotalQuery:
- """Query timeseries `power_inverter.reactive_power_total`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the power_inverter.reactive_power_total timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 power_inverter.reactive_power_total timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.reactive_power_total(limit=5).retrieve()
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return PowerInverterReactivePowerTotalQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `power_inverter.reactive_power_total`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of power inverters to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries power_inverter.reactive_power_total.
-
- Examples:
-
- List power_inverter.reactive_power_total and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> power_inverters = client.power_inverter.reactive_power_total.list(limit=5)
-
- """
- filter_ = _create_power_inverter_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_reactive_power_total(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_reactive_power_total(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "reactive_power_total",
-) -> dict[str, list[str]]:
- properties = {"reactive_power_total"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("reactive_power_total"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["reactive_power_total"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/rotor.py b/examples/windmill/_api/rotor.py
deleted file mode 100644
index 0b62423b6..000000000
--- a/examples/windmill/_api/rotor.py
+++ /dev/null
@@ -1,444 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Rotor,
- RotorWrite,
- RotorFields,
- RotorList,
- RotorWriteList,
- RotorTextFields,
-)
-from windmill.data_classes._rotor import (
- RotorQuery,
- _ROTOR_PROPERTIES_BY_FIELD,
- _create_rotor_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.rotor_rotor_speed_controller import RotorRotorSpeedControllerAPI
-from windmill._api.rotor_rpm_low_speed_shaft import RotorRpmLowSpeedShaftAPI
-from windmill._api.rotor_query import RotorQueryAPI
-
-
-class RotorAPI(NodeAPI[Rotor, RotorWrite, RotorList, RotorWriteList]):
- _view_id = dm.ViewId("power-models", "Rotor", "1")
- _properties_by_field = _ROTOR_PROPERTIES_BY_FIELD
- _class_type = Rotor
- _class_list = RotorList
- _class_write_list = RotorWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.rotor_speed_controller = RotorRotorSpeedControllerAPI(client, self._view_id)
- self.rpm_low_speed_shaft = RotorRpmLowSpeedShaftAPI(client, self._view_id)
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> RotorQueryAPI[RotorList]:
- """Query starting at rotors.
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for rotors.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(RotorList)
- return RotorQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- rotor: RotorWrite | Sequence[RotorWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) rotors.
-
- Args:
- rotor: Rotor or sequence of rotors to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new rotor:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import RotorWrite
- >>> client = WindmillClient()
- >>> rotor = RotorWrite(external_id="my_rotor", ...)
- >>> result = client.rotor.apply(rotor)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.rotor.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(rotor, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more rotor.
-
- Args:
- external_id: External id of the rotor to delete.
- space: The space where all the rotor are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete rotor by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.rotor.delete("my_rotor")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.rotor.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Rotor | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> RotorList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Rotor | RotorList | None:
- """Retrieve one or more rotors by id(s).
-
- Args:
- external_id: External id or list of external ids of the rotors.
- space: The space where all the rotors are located.
-
- Returns:
- The requested rotors.
-
- Examples:
-
- Retrieve rotor by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor = client.rotor.retrieve("my_rotor")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: RotorTextFields | SequenceNotStr[RotorTextFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: RotorFields | SequenceNotStr[RotorFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> RotorList:
- """Search rotors
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results rotors matching the query.
-
- Examples:
-
- Search for 'my_rotor' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotors = client.rotor.search('my_rotor')
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: RotorFields | SequenceNotStr[RotorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: RotorFields | SequenceNotStr[RotorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: RotorFields | SequenceNotStr[RotorFields],
- property: RotorFields | SequenceNotStr[RotorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: RotorFields | SequenceNotStr[RotorFields] | None = None,
- property: RotorFields | SequenceNotStr[RotorFields] | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across rotors
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count rotors in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.rotor.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: RotorFields,
- interval: float,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for rotors
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> RotorQuery:
- """Start a query for rotors."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return RotorQuery(self._client)
-
- def select(self) -> RotorQuery:
- """Start selecting from rotors."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return RotorQuery(self._client)
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: RotorFields | Sequence[RotorFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> RotorList:
- """List/filter rotors
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested rotors
-
- Examples:
-
- List rotors and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotors = client.rotor.list(limit=5)
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/rotor_query.py b/examples/windmill/_api/rotor_query.py
deleted file mode 100644
index 01cb90af5..000000000
--- a/examples/windmill/_api/rotor_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Rotor,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class RotorQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Rotor", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Rotor,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/rotor_rotor_speed_controller.py b/examples/windmill/_api/rotor_rotor_speed_controller.py
deleted file mode 100644
index 519d2619c..000000000
--- a/examples/windmill/_api/rotor_rotor_speed_controller.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._rotor import _create_rotor_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["rotor_speed_controller", "rpm_low_speed_shaft"]
-
-
-class RotorRotorSpeedControllerQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `rotor.rotor_speed_controller` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_rotor_speed_controller' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rotor_speed_controller(external_id="my_rotor_speed_controller").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `rotor.rotor_speed_controller` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_rotor_speed_controller' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rotor_speed_controller(external_id="my_rotor_speed_controller").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "rotor_speed_controller",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `rotor.rotor_speed_controller` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to rotor_speed_controller
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_rotor_speed_controller' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rotor_speed_controller(external_id="my_rotor_speed_controller").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "rotor_speed_controller",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `rotor.rotor_speed_controller` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to rotor_speed_controller
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_rotor_speed_controller' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rotor_speed_controller(
- ... external_id="my_rotor_speed_controller").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "rotor_speed_controller"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_rotor_speed_controller(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "rotor_speed_controller":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class RotorRotorSpeedControllerAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> RotorRotorSpeedControllerQuery:
- """Query timeseries `rotor.rotor_speed_controller`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the rotor.rotor_speed_controller timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 rotor.rotor_speed_controller timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotors = client.rotor.rotor_speed_controller(limit=5).retrieve()
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return RotorRotorSpeedControllerQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `rotor.rotor_speed_controller`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries rotor.rotor_speed_controller.
-
- Examples:
-
- List rotor.rotor_speed_controller and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotors = client.rotor.rotor_speed_controller.list(limit=5)
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_rotor_speed_controller(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_rotor_speed_controller(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "rotor_speed_controller",
-) -> dict[str, list[str]]:
- properties = {"rotor_speed_controller"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("rotor_speed_controller"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["rotor_speed_controller"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/rotor_rpm_low_speed_shaft.py b/examples/windmill/_api/rotor_rpm_low_speed_shaft.py
deleted file mode 100644
index b8c447fe4..000000000
--- a/examples/windmill/_api/rotor_rpm_low_speed_shaft.py
+++ /dev/null
@@ -1,493 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._rotor import _create_rotor_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal["rotor_speed_controller", "rpm_low_speed_shaft"]
-
-
-class RotorRpmLowSpeedShaftQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `rotor.rpm_low_speed_shaft` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_rpm_low_speed_shaft' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rpm_low_speed_shaft(external_id="my_rpm_low_speed_shaft").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `rotor.rpm_low_speed_shaft` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_rpm_low_speed_shaft' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rpm_low_speed_shaft(external_id="my_rpm_low_speed_shaft").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "rpm_low_speed_shaft",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `rotor.rpm_low_speed_shaft` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to rpm_low_speed_shaft
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_rpm_low_speed_shaft' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rpm_low_speed_shaft(external_id="my_rpm_low_speed_shaft").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "rpm_low_speed_shaft",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `rotor.rpm_low_speed_shaft` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to rpm_low_speed_shaft
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_rpm_low_speed_shaft' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> rotor_datapoints = client.rotor.rpm_low_speed_shaft(
- ... external_id="my_rpm_low_speed_shaft").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "rpm_low_speed_shaft"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_rpm_low_speed_shaft(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "rpm_low_speed_shaft":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class RotorRpmLowSpeedShaftAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> RotorRpmLowSpeedShaftQuery:
- """Query timeseries `rotor.rpm_low_speed_shaft`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the rotor.rpm_low_speed_shaft timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 rotor.rpm_low_speed_shaft timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotors = client.rotor.rpm_low_speed_shaft(limit=5).retrieve()
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
-
- return RotorRpmLowSpeedShaftQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `rotor.rpm_low_speed_shaft`
-
- Args:
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of rotors to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries rotor.rpm_low_speed_shaft.
-
- Examples:
-
- List rotor.rpm_low_speed_shaft and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> rotors = client.rotor.rpm_low_speed_shaft.list(limit=5)
-
- """
- filter_ = _create_rotor_filter(
- self._view_id,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_rpm_low_speed_shaft(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_rpm_low_speed_shaft(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "rpm_low_speed_shaft",
-) -> dict[str, list[str]]:
- properties = {"rpm_low_speed_shaft"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("rpm_low_speed_shaft"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["rpm_low_speed_shaft"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position.py b/examples/windmill/_api/sensor_position.py
deleted file mode 100644
index 41f407231..000000000
--- a/examples/windmill/_api/sensor_position.py
+++ /dev/null
@@ -1,508 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- SensorPosition,
- SensorPositionWrite,
- SensorPositionFields,
- SensorPositionList,
- SensorPositionWriteList,
- SensorPositionTextFields,
-)
-from windmill.data_classes._sensor_position import (
- SensorPositionQuery,
- _SENSORPOSITION_PROPERTIES_BY_FIELD,
- _create_sensor_position_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.sensor_position_edgewise_bend_mom_crosstalk_corrected import (
- SensorPositionEdgewiseBendMomCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_edgewise_bend_mom_offset import SensorPositionEdgewiseBendMomOffsetAPI
-from windmill._api.sensor_position_edgewise_bend_mom_offset_crosstalk_corrected import (
- SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_edgewisewise_bend_mom import SensorPositionEdgewisewiseBendMomAPI
-from windmill._api.sensor_position_flapwise_bend_mom import SensorPositionFlapwiseBendMomAPI
-from windmill._api.sensor_position_flapwise_bend_mom_crosstalk_corrected import (
- SensorPositionFlapwiseBendMomCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_flapwise_bend_mom_offset import SensorPositionFlapwiseBendMomOffsetAPI
-from windmill._api.sensor_position_flapwise_bend_mom_offset_crosstalk_corrected import (
- SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedAPI,
-)
-from windmill._api.sensor_position_query import SensorPositionQueryAPI
-
-
-class SensorPositionAPI(NodeAPI[SensorPosition, SensorPositionWrite, SensorPositionList, SensorPositionWriteList]):
- _view_id = dm.ViewId("power-models", "SensorPosition", "1")
- _properties_by_field = _SENSORPOSITION_PROPERTIES_BY_FIELD
- _class_type = SensorPosition
- _class_list = SensorPositionList
- _class_write_list = SensorPositionWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.edgewise_bend_mom_crosstalk_corrected = SensorPositionEdgewiseBendMomCrosstalkCorrectedAPI(
- client, self._view_id
- )
- self.edgewise_bend_mom_offset = SensorPositionEdgewiseBendMomOffsetAPI(client, self._view_id)
- self.edgewise_bend_mom_offset_crosstalk_corrected = SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedAPI(
- client, self._view_id
- )
- self.edgewisewise_bend_mom = SensorPositionEdgewisewiseBendMomAPI(client, self._view_id)
- self.flapwise_bend_mom = SensorPositionFlapwiseBendMomAPI(client, self._view_id)
- self.flapwise_bend_mom_crosstalk_corrected = SensorPositionFlapwiseBendMomCrosstalkCorrectedAPI(
- client, self._view_id
- )
- self.flapwise_bend_mom_offset = SensorPositionFlapwiseBendMomOffsetAPI(client, self._view_id)
- self.flapwise_bend_mom_offset_crosstalk_corrected = SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedAPI(
- client, self._view_id
- )
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> SensorPositionQueryAPI[SensorPositionList]:
- """Query starting at sensor positions.
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for sensor positions.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(SensorPositionList)
- return SensorPositionQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- sensor_position: SensorPositionWrite | Sequence[SensorPositionWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) sensor positions.
-
- Args:
- sensor_position: Sensor position or sequence of sensor positions to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new sensor_position:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import SensorPositionWrite
- >>> client = WindmillClient()
- >>> sensor_position = SensorPositionWrite(external_id="my_sensor_position", ...)
- >>> result = client.sensor_position.apply(sensor_position)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.sensor_position.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(sensor_position, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more sensor position.
-
- Args:
- external_id: External id of the sensor position to delete.
- space: The space where all the sensor position are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete sensor_position by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.sensor_position.delete("my_sensor_position")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.sensor_position.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> SensorPosition | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> SensorPositionList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> SensorPosition | SensorPositionList | None:
- """Retrieve one or more sensor positions by id(s).
-
- Args:
- external_id: External id or list of external ids of the sensor positions.
- space: The space where all the sensor positions are located.
-
- Returns:
- The requested sensor positions.
-
- Examples:
-
- Retrieve sensor_position by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position = client.sensor_position.retrieve("my_sensor_position")
-
- """
- return self._retrieve(external_id, space)
-
- def search(
- self,
- query: str,
- properties: SensorPositionTextFields | SequenceNotStr[SensorPositionTextFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: SensorPositionFields | SequenceNotStr[SensorPositionFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> SensorPositionList:
- """Search sensor positions
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results sensor positions matching the query.
-
- Examples:
-
- Search for 'my_sensor_position' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.search('my_sensor_position')
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: SensorPositionFields | SequenceNotStr[SensorPositionFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: SensorPositionFields | SequenceNotStr[SensorPositionFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: SensorPositionFields | SequenceNotStr[SensorPositionFields],
- property: SensorPositionFields | SequenceNotStr[SensorPositionFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: SensorPositionFields | SequenceNotStr[SensorPositionFields] | None = None,
- property: SensorPositionFields | SequenceNotStr[SensorPositionFields] | None = None,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across sensor positions
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count sensor positions in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.sensor_position.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=None,
- search_properties=None,
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: SensorPositionFields,
- interval: float,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for sensor positions
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- None,
- None,
- limit,
- filter_,
- )
-
- def query(self) -> SensorPositionQuery:
- """Start a query for sensor positions."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return SensorPositionQuery(self._client)
-
- def select(self) -> SensorPositionQuery:
- """Start selecting from sensor positions."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return SensorPositionQuery(self._client)
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: SensorPositionFields | Sequence[SensorPositionFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> SensorPositionList:
- """List/filter sensor positions
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- List of requested sensor positions
-
- Examples:
-
- List sensor positions and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
diff --git a/examples/windmill/_api/sensor_position_edgewise_bend_mom_crosstalk_corrected.py b/examples/windmill/_api/sensor_position_edgewise_bend_mom_crosstalk_corrected.py
deleted file mode 100644
index a7bc62cc2..000000000
--- a/examples/windmill/_api/sensor_position_edgewise_bend_mom_crosstalk_corrected.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionEdgewiseBendMomCrosstalkCorrectedQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.edgewise_bend_mom_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_crosstalk_corrected(external_id="my_edgewise_bend_mom_crosstalk_corrected").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.edgewise_bend_mom_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_crosstalk_corrected(external_id="my_edgewise_bend_mom_crosstalk_corrected").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_crosstalk_corrected",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.edgewise_bend_mom_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewise_bend_mom_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_crosstalk_corrected(external_id="my_edgewise_bend_mom_crosstalk_corrected").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_crosstalk_corrected",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.edgewise_bend_mom_crosstalk_corrected` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewise_bend_mom_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_edgewise_bend_mom_crosstalk_corrected' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_crosstalk_corrected(
- ... external_id="my_edgewise_bend_mom_crosstalk_corrected").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_crosstalk_corrected"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_crosstalk_corrected(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "edgewise_bend_mom_crosstalk_corrected":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionEdgewiseBendMomCrosstalkCorrectedAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionEdgewiseBendMomCrosstalkCorrectedQuery:
- """Query timeseries `sensor_position.edgewise_bend_mom_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.edgewise_bend_mom_crosstalk_corrected timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.edgewise_bend_mom_crosstalk_corrected timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewise_bend_mom_crosstalk_corrected(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionEdgewiseBendMomCrosstalkCorrectedQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.edgewise_bend_mom_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.edgewise_bend_mom_crosstalk_corrected.
-
- Examples:
-
- List sensor_position.edgewise_bend_mom_crosstalk_corrected and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewise_bend_mom_crosstalk_corrected.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_crosstalk_corrected(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_crosstalk_corrected(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_crosstalk_corrected",
-) -> dict[str, list[str]]:
- properties = {"edgewise_bend_mom_crosstalk_corrected"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("edgewise_bend_mom_crosstalk_corrected"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["edgewise_bend_mom_crosstalk_corrected"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_edgewise_bend_mom_offset.py b/examples/windmill/_api/sensor_position_edgewise_bend_mom_offset.py
deleted file mode 100644
index a24e7c912..000000000
--- a/examples/windmill/_api/sensor_position_edgewise_bend_mom_offset.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionEdgewiseBendMomOffsetQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.edgewise_bend_mom_offset` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_offset' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset(external_id="my_edgewise_bend_mom_offset").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.edgewise_bend_mom_offset` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_offset' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset(external_id="my_edgewise_bend_mom_offset").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.edgewise_bend_mom_offset` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewise_bend_mom_offset
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_offset' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset(external_id="my_edgewise_bend_mom_offset").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.edgewise_bend_mom_offset` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewise_bend_mom_offset
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_edgewise_bend_mom_offset' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset(
- ... external_id="my_edgewise_bend_mom_offset").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_offset(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "edgewise_bend_mom_offset":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionEdgewiseBendMomOffsetAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionEdgewiseBendMomOffsetQuery:
- """Query timeseries `sensor_position.edgewise_bend_mom_offset`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.edgewise_bend_mom_offset timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.edgewise_bend_mom_offset timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewise_bend_mom_offset(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionEdgewiseBendMomOffsetQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.edgewise_bend_mom_offset`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.edgewise_bend_mom_offset.
-
- Examples:
-
- List sensor_position.edgewise_bend_mom_offset and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewise_bend_mom_offset.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_offset(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_offset(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset",
-) -> dict[str, list[str]]:
- properties = {"edgewise_bend_mom_offset"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("edgewise_bend_mom_offset"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["edgewise_bend_mom_offset"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_edgewise_bend_mom_offset_crosstalk_corrected.py b/examples/windmill/_api/sensor_position_edgewise_bend_mom_offset_crosstalk_corrected.py
deleted file mode 100644
index cc7f34c8a..000000000
--- a/examples/windmill/_api/sensor_position_edgewise_bend_mom_offset_crosstalk_corrected.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.edgewise_bend_mom_offset_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_offset_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset_crosstalk_corrected(external_id="my_edgewise_bend_mom_offset_crosstalk_corrected").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.edgewise_bend_mom_offset_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_offset_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset_crosstalk_corrected(external_id="my_edgewise_bend_mom_offset_crosstalk_corrected").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset_crosstalk_corrected",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.edgewise_bend_mom_offset_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewise_bend_mom_offset_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewise_bend_mom_offset_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset_crosstalk_corrected(external_id="my_edgewise_bend_mom_offset_crosstalk_corrected").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset_crosstalk_corrected",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.edgewise_bend_mom_offset_crosstalk_corrected` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewise_bend_mom_offset_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_edgewise_bend_mom_offset_crosstalk_corrected' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewise_bend_mom_offset_crosstalk_corrected(
- ... external_id="my_edgewise_bend_mom_offset_crosstalk_corrected").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset_crosstalk_corrected"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_offset_crosstalk_corrected(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "edgewise_bend_mom_offset_crosstalk_corrected":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedQuery:
- """Query timeseries `sensor_position.edgewise_bend_mom_offset_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.edgewise_bend_mom_offset_crosstalk_corrected timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.edgewise_bend_mom_offset_crosstalk_corrected timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewise_bend_mom_offset_crosstalk_corrected(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionEdgewiseBendMomOffsetCrosstalkCorrectedQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.edgewise_bend_mom_offset_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.edgewise_bend_mom_offset_crosstalk_corrected.
-
- Examples:
-
- List sensor_position.edgewise_bend_mom_offset_crosstalk_corrected and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewise_bend_mom_offset_crosstalk_corrected.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_offset_crosstalk_corrected(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_edgewise_bend_mom_offset_crosstalk_corrected(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "edgewise_bend_mom_offset_crosstalk_corrected",
-) -> dict[str, list[str]]:
- properties = {"edgewise_bend_mom_offset_crosstalk_corrected"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("edgewise_bend_mom_offset_crosstalk_corrected"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["edgewise_bend_mom_offset_crosstalk_corrected"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_edgewisewise_bend_mom.py b/examples/windmill/_api/sensor_position_edgewisewise_bend_mom.py
deleted file mode 100644
index ba5760324..000000000
--- a/examples/windmill/_api/sensor_position_edgewisewise_bend_mom.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionEdgewisewiseBendMomQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.edgewisewise_bend_mom` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewisewise_bend_mom' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewisewise_bend_mom(external_id="my_edgewisewise_bend_mom").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.edgewisewise_bend_mom` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewisewise_bend_mom' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewisewise_bend_mom(external_id="my_edgewisewise_bend_mom").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewisewise_bend_mom",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.edgewisewise_bend_mom` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewisewise_bend_mom
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_edgewisewise_bend_mom' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewisewise_bend_mom(external_id="my_edgewisewise_bend_mom").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "edgewisewise_bend_mom",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.edgewisewise_bend_mom` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to edgewisewise_bend_mom
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_edgewisewise_bend_mom' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.edgewisewise_bend_mom(
- ... external_id="my_edgewisewise_bend_mom").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "edgewisewise_bend_mom"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_edgewisewise_bend_mom(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "edgewisewise_bend_mom":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionEdgewisewiseBendMomAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionEdgewisewiseBendMomQuery:
- """Query timeseries `sensor_position.edgewisewise_bend_mom`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.edgewisewise_bend_mom timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.edgewisewise_bend_mom timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewisewise_bend_mom(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionEdgewisewiseBendMomQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.edgewisewise_bend_mom`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.edgewisewise_bend_mom.
-
- Examples:
-
- List sensor_position.edgewisewise_bend_mom and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.edgewisewise_bend_mom.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_edgewisewise_bend_mom(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_edgewisewise_bend_mom(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "edgewisewise_bend_mom",
-) -> dict[str, list[str]]:
- properties = {"edgewisewise_bend_mom"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("edgewisewise_bend_mom"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["edgewisewise_bend_mom"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_flapwise_bend_mom.py b/examples/windmill/_api/sensor_position_flapwise_bend_mom.py
deleted file mode 100644
index ecad9a06f..000000000
--- a/examples/windmill/_api/sensor_position_flapwise_bend_mom.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionFlapwiseBendMomQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.flapwise_bend_mom` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom(external_id="my_flapwise_bend_mom").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.flapwise_bend_mom` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom(external_id="my_flapwise_bend_mom").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.flapwise_bend_mom` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom(external_id="my_flapwise_bend_mom").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.flapwise_bend_mom` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_flapwise_bend_mom' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom(
- ... external_id="my_flapwise_bend_mom").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "flapwise_bend_mom":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionFlapwiseBendMomAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionFlapwiseBendMomQuery:
- """Query timeseries `sensor_position.flapwise_bend_mom`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.flapwise_bend_mom timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.flapwise_bend_mom timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionFlapwiseBendMomQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.flapwise_bend_mom`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.flapwise_bend_mom.
-
- Examples:
-
- List sensor_position.flapwise_bend_mom and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom",
-) -> dict[str, list[str]]:
- properties = {"flapwise_bend_mom"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("flapwise_bend_mom"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["flapwise_bend_mom"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_flapwise_bend_mom_crosstalk_corrected.py b/examples/windmill/_api/sensor_position_flapwise_bend_mom_crosstalk_corrected.py
deleted file mode 100644
index 13fd1f935..000000000
--- a/examples/windmill/_api/sensor_position_flapwise_bend_mom_crosstalk_corrected.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionFlapwiseBendMomCrosstalkCorrectedQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.flapwise_bend_mom_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_crosstalk_corrected(external_id="my_flapwise_bend_mom_crosstalk_corrected").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.flapwise_bend_mom_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_crosstalk_corrected(external_id="my_flapwise_bend_mom_crosstalk_corrected").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_crosstalk_corrected",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.flapwise_bend_mom_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_crosstalk_corrected(external_id="my_flapwise_bend_mom_crosstalk_corrected").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_crosstalk_corrected",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.flapwise_bend_mom_crosstalk_corrected` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_flapwise_bend_mom_crosstalk_corrected' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_crosstalk_corrected(
- ... external_id="my_flapwise_bend_mom_crosstalk_corrected").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_crosstalk_corrected"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_crosstalk_corrected(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "flapwise_bend_mom_crosstalk_corrected":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionFlapwiseBendMomCrosstalkCorrectedAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionFlapwiseBendMomCrosstalkCorrectedQuery:
- """Query timeseries `sensor_position.flapwise_bend_mom_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.flapwise_bend_mom_crosstalk_corrected timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.flapwise_bend_mom_crosstalk_corrected timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom_crosstalk_corrected(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionFlapwiseBendMomCrosstalkCorrectedQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.flapwise_bend_mom_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.flapwise_bend_mom_crosstalk_corrected.
-
- Examples:
-
- List sensor_position.flapwise_bend_mom_crosstalk_corrected and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom_crosstalk_corrected.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_crosstalk_corrected(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_crosstalk_corrected(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_crosstalk_corrected",
-) -> dict[str, list[str]]:
- properties = {"flapwise_bend_mom_crosstalk_corrected"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("flapwise_bend_mom_crosstalk_corrected"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["flapwise_bend_mom_crosstalk_corrected"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_flapwise_bend_mom_offset.py b/examples/windmill/_api/sensor_position_flapwise_bend_mom_offset.py
deleted file mode 100644
index 68eb401c2..000000000
--- a/examples/windmill/_api/sensor_position_flapwise_bend_mom_offset.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionFlapwiseBendMomOffsetQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.flapwise_bend_mom_offset` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_offset' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset(external_id="my_flapwise_bend_mom_offset").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.flapwise_bend_mom_offset` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_offset' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset(external_id="my_flapwise_bend_mom_offset").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.flapwise_bend_mom_offset` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom_offset
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_offset' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset(external_id="my_flapwise_bend_mom_offset").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.flapwise_bend_mom_offset` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom_offset
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_flapwise_bend_mom_offset' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset(
- ... external_id="my_flapwise_bend_mom_offset").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_offset(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "flapwise_bend_mom_offset":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionFlapwiseBendMomOffsetAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionFlapwiseBendMomOffsetQuery:
- """Query timeseries `sensor_position.flapwise_bend_mom_offset`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.flapwise_bend_mom_offset timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.flapwise_bend_mom_offset timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom_offset(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionFlapwiseBendMomOffsetQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.flapwise_bend_mom_offset`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.flapwise_bend_mom_offset.
-
- Examples:
-
- List sensor_position.flapwise_bend_mom_offset and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom_offset.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_offset(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_offset(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset",
-) -> dict[str, list[str]]:
- properties = {"flapwise_bend_mom_offset"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("flapwise_bend_mom_offset"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["flapwise_bend_mom_offset"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_flapwise_bend_mom_offset_crosstalk_corrected.py b/examples/windmill/_api/sensor_position_flapwise_bend_mom_offset_crosstalk_corrected.py
deleted file mode 100644
index 12d6bc026..000000000
--- a/examples/windmill/_api/sensor_position_flapwise_bend_mom_offset_crosstalk_corrected.py
+++ /dev/null
@@ -1,515 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import Literal, cast
-
-import pandas as pd
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, DatapointsArrayList, DatapointsList, TimeSeriesList
-from cognite.client.data_classes.datapoints import Aggregate
-from windmill.data_classes._sensor_position import _create_sensor_position_filter
-from windmill.data_classes._core import QueryStep, DataClassQueryBuilder, DomainModelList
-from windmill._api._core import DEFAULT_LIMIT_READ
-
-
-ColumnNames = Literal[
- "edgewise_bend_mom_crosstalk_corrected",
- "edgewise_bend_mom_offset",
- "edgewise_bend_mom_offset_crosstalk_corrected",
- "edgewisewise_bend_mom",
- "flapwise_bend_mom",
- "flapwise_bend_mom_crosstalk_corrected",
- "flapwise_bend_mom_offset",
- "flapwise_bend_mom_offset_crosstalk_corrected",
- "position",
-]
-
-
-class SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedQuery:
- def __init__(
- self,
- client: CogniteClient,
- view_id: dm.ViewId,
- timeseries_limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ):
- self._client = client
- self._view_id = view_id
- self._timeseries_limit = timeseries_limit
- self._filter = filter
-
- def retrieve(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsList:
- """`Retrieve datapoints for the `sensor_position.flapwise_bend_mom_offset_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_offset_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset_crosstalk_corrected(external_id="my_flapwise_bend_mom_offset_crosstalk_corrected").retrieve(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsList([])
-
- def retrieve_arrays(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- ) -> DatapointsArrayList:
- """`Retrieve numpy arrays for the `sensor_position.flapwise_bend_mom_offset_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit (int | None): Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points (bool): Whether to include outside points. Not allowed when fetching aggregates. Default: False
-
- Returns:
- A ``DatapointsArrayList`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_offset_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset_crosstalk_corrected(external_id="my_flapwise_bend_mom_offset_crosstalk_corrected").retrieve_array(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- # Missing overload in SDK
- return self._client.time_series.data.retrieve_arrays( # type: ignore[return-value]
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- )
- else:
- return DatapointsArrayList([])
-
- def retrieve_dataframe(
- self,
- start: int | str | datetime.datetime | None = None,
- end: int | str | datetime.datetime | None = None,
- *,
- aggregates: Aggregate | list[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- limit: int | None = None,
- include_outside_points: bool = False,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset_crosstalk_corrected",
- ) -> pd.DataFrame:
- """`Retrieve DataFrames for the `sensor_position.flapwise_bend_mom_offset_crosstalk_corrected` timeseries.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start. Default: 1970-01-01 UTC.
- end: Exclusive end. Default: "now"
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom_offset_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- we are using the time-ago format to get raw data for the 'my_flapwise_bend_mom_offset_crosstalk_corrected' from 2 weeks ago up until now::
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset_crosstalk_corrected(external_id="my_flapwise_bend_mom_offset_crosstalk_corrected").retrieve_dataframe(start="2w-ago")
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- limit=limit,
- include_outside_points=include_outside_points,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_dataframe_in_tz(
- self,
- start: datetime.datetime,
- end: datetime.datetime,
- *,
- aggregates: Aggregate | Sequence[Aggregate] | None = None,
- granularity: str | None = None,
- target_unit: str | None = None,
- target_unit_system: str | None = None,
- uniform_index: bool = False,
- include_aggregate_name: bool = True,
- include_granularity_name: bool = False,
- column_names: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset_crosstalk_corrected",
- ) -> pd.DataFrame:
- """Retrieve DataFrames for the `sensor_position.flapwise_bend_mom_offset_crosstalk_corrected` timeseries in Timezone.
-
- **Performance guide**:
- In order to retrieve millions of datapoints as efficiently as possible, here are a few guidelines:
-
- 1. For the best speed, and significantly lower memory usage, consider using ``retrieve_arrays(...)`` which uses ``numpy.ndarrays`` for data storage.
- 2. Only unlimited queries with (``limit=None``) are fetched in parallel, so specifying a large finite ``limit`` like 1 million, comes with severe performance penalty as data is fetched serially.
- 3. Try to avoid specifying `start` and `end` to be very far from the actual data: If you had data from 2000 to 2015, don't set start=0 (1970).
-
- Args:
- start: Inclusive start.
- end: Exclusive end
- aggregates: Single aggregate or list of aggregates to retrieve. Default: None (raw datapoints returned)
- granularity The granularity to fetch aggregates at. e.g. '15s', '2h', '10d'. Default: None.
- target_unit: The unit_external_id of the data points returned. If the time series does not have an unit_external_id that can be converted to the target_unit, an error will be returned. Cannot be used with target_unit_system.
- target_unit_system: The unit system of the data points returned. Cannot be used with target_unit.
- limit: Maximum number of datapoints to return for each time series. Default: None (no limit)
- include_outside_points: Whether to include outside points. Not allowed when fetching aggregates. Default: False
- uniform_index: If only querying aggregates AND a single granularity is used, AND no limit is used, specifying `uniform_index=True` will return a dataframe with an equidistant datetime index from the earliest `start` to the latest `end` (missing values will be NaNs). If these requirements are not met, a ValueError is raised. Default: False
- include_aggregate_name: Include 'aggregate' in the column name, e.g. `my-ts|average`. Ignored for raw time series. Default: True
- include_granularity_name: Include 'granularity' in the column name, e.g. `my-ts|12h`. Added after 'aggregate' when present. Ignored for raw time series. Default: False
- column_names: Which property to use for column names. Defauts to flapwise_bend_mom_offset_crosstalk_corrected
-
-
- Returns:
- A ``DataFrame`` with the requested datapoints.
-
- Examples:
-
- In this example,
- get weekly aggregates for the 'my_flapwise_bend_mom_offset_crosstalk_corrected' for the first month of 2023 in Oslo time:
-
- >>> from windmill import WindmillClient
- >>> from datetime import datetime, timezone
- >>> client = WindmillClient()
- >>> sensor_position_datapoints = client.sensor_position.flapwise_bend_mom_offset_crosstalk_corrected(
- ... external_id="my_flapwise_bend_mom_offset_crosstalk_corrected").retrieve_dataframe_in_timezone(
- ... datetime(2023, 1, 1, tzinfo=ZoneInfo("Europe/Oslo")),
- ... datetime(2023, 1, 2, tzinfo=ZoneInfo("Europe/Oslo")),
- ... aggregates="average",
- ... granularity="1week",
- ... )
- """
- external_ids = self._retrieve_timeseries_external_ids_with_extra(column_names)
- if external_ids:
- df = self._client.time_series.data.retrieve_dataframe_in_tz(
- external_id=list(external_ids),
- start=start,
- end=end,
- aggregates=aggregates, # type: ignore[arg-type]
- granularity=granularity,
- target_unit=target_unit,
- target_unit_system=target_unit_system,
- uniform_index=uniform_index,
- include_aggregate_name=include_aggregate_name,
- include_granularity_name=include_granularity_name,
- )
- is_aggregate = aggregates is not None
- return self._rename_columns(
- external_ids,
- df,
- column_names,
- is_aggregate and include_aggregate_name,
- is_aggregate and include_granularity_name,
- )
- else:
- return pd.DataFrame()
-
- def retrieve_latest(
- self,
- before: None | int | str | datetime.datetime = None,
- ) -> Datapoints | DatapointsList | None:
- external_ids = self._retrieve_timeseries_external_ids_with_extra()
- if external_ids:
- return self._client.time_series.data.retrieve_latest(
- external_id=list(external_ids),
- before=before,
- )
- else:
- return None
-
- def _retrieve_timeseries_external_ids_with_extra(
- self, extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset_crosstalk_corrected"
- ) -> dict[str, list[str]]:
- return _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_offset_crosstalk_corrected(
- self._client,
- self._view_id,
- self._filter,
- self._timeseries_limit,
- extra_properties,
- )
-
- @staticmethod
- def _rename_columns(
- external_ids: dict[str, list[str]],
- df: pd.DataFrame,
- column_names: ColumnNames | list[ColumnNames],
- include_aggregate_name: bool,
- include_granularity_name: bool,
- ) -> pd.DataFrame:
- if isinstance(column_names, str) and column_names == "flapwise_bend_mom_offset_crosstalk_corrected":
- return df
- splits = sum(included for included in [include_aggregate_name, include_granularity_name])
- if splits == 0:
- df.columns = ["-".join(external_ids[external_id]) for external_id in df.columns] # type: ignore[assignment]
- else:
- column_parts = (col.rsplit("|", maxsplit=splits) for col in df.columns)
- df.columns = [ # type: ignore[assignment]
- "-".join(external_ids[external_id]) + "|" + "|".join(parts) for external_id, *parts in column_parts
- ]
- return df
-
-
-class SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedAPI:
- def __init__(self, client: CogniteClient, view_id: dm.ViewId):
- self._client = client
- self._view_id = view_id
-
- def __call__(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedQuery:
- """Query timeseries `sensor_position.flapwise_bend_mom_offset_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query object that can be used to retrieve datapoins for the sensor_position.flapwise_bend_mom_offset_crosstalk_corrected timeseries
- selected in this method.
-
- Examples:
-
- Retrieve all data for 5 sensor_position.flapwise_bend_mom_offset_crosstalk_corrected timeseries:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom_offset_crosstalk_corrected(limit=5).retrieve()
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
-
- return SensorPositionFlapwiseBendMomOffsetCrosstalkCorrectedQuery(
- client=self._client,
- view_id=self._view_id,
- timeseries_limit=limit,
- filter=filter_,
- )
-
- def list(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> TimeSeriesList:
- """List timeseries `sensor_position.flapwise_bend_mom_offset_crosstalk_corrected`
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of sensor positions to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- List of Timeseries sensor_position.flapwise_bend_mom_offset_crosstalk_corrected.
-
- Examples:
-
- List sensor_position.flapwise_bend_mom_offset_crosstalk_corrected and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> sensor_positions = client.sensor_position.flapwise_bend_mom_offset_crosstalk_corrected.list(limit=5)
-
- """
- filter_ = _create_sensor_position_filter(
- self._view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- filter,
- )
- external_ids = _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_offset_crosstalk_corrected(
- self._client, self._view_id, filter_, limit
- )
- if external_ids:
- return self._client.time_series.retrieve_multiple(external_ids=list(external_ids))
- else:
- return TimeSeriesList([])
-
-
-def _retrieve_timeseries_external_ids_with_extra_flapwise_bend_mom_offset_crosstalk_corrected(
- client: CogniteClient,
- view_id: dm.ViewId,
- filter_: dm.Filter | None,
- limit: int,
- extra_properties: ColumnNames | list[ColumnNames] = "flapwise_bend_mom_offset_crosstalk_corrected",
-) -> dict[str, list[str]]:
- properties = {"flapwise_bend_mom_offset_crosstalk_corrected"}
- if isinstance(extra_properties, str):
- properties.add(extra_properties)
- extra_properties_list = [extra_properties]
- elif isinstance(extra_properties, list):
- properties.update(extra_properties)
- extra_properties_list = extra_properties
- else:
- raise ValueError(f"Invalid value for extra_properties: {extra_properties}")
-
- has_data = dm.filters.HasData(views=[view_id])
- has_property = dm.filters.Exists(property=view_id.as_property_ref("flapwise_bend_mom_offset_crosstalk_corrected"))
- filter_ = dm.filters.And(filter_, has_data, has_property) if filter_ else dm.filters.And(has_data, has_property)
-
- builder = DataClassQueryBuilder[DomainModelList](None)
- builder.append(
- QueryStep(
- name="nodes",
- expression=dm.query.NodeResultSetExpression(filter=filter_),
- max_retrieve_limit=limit,
- select=dm.query.Select([dm.query.SourceSelector(view_id, list(properties))]),
- )
- )
- builder.execute_query(client)
-
- output: dict[str, list[str]] = {}
- for node in builder[0].results:
- if node.properties is None:
- continue
- view_prop = node.properties[view_id]
- key = view_prop["flapwise_bend_mom_offset_crosstalk_corrected"]
- values = [prop_ for prop in extra_properties_list if isinstance(prop_ := view_prop.get(prop, "MISSING"), str)]
- if isinstance(key, str):
- output[key] = values
- elif isinstance(key, list):
- for k in key:
- if isinstance(k, str):
- output[k] = values
- return output
diff --git a/examples/windmill/_api/sensor_position_query.py b/examples/windmill/_api/sensor_position_query.py
deleted file mode 100644
index f5c04d93e..000000000
--- a/examples/windmill/_api/sensor_position_query.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- SensorPosition,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-
-class SensorPositionQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "SensorPosition", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=SensorPosition,
- max_retrieve_limit=limit,
- )
- )
-
- def query(
- self,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- return self._query()
diff --git a/examples/windmill/_api/windmill.py b/examples/windmill/_api/windmill.py
deleted file mode 100644
index 03f6653b8..000000000
--- a/examples/windmill/_api/windmill.py
+++ /dev/null
@@ -1,832 +0,0 @@
-from __future__ import annotations
-
-from collections.abc import Sequence
-from typing import overload, Literal
-import warnings
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes.data_modeling.instances import InstanceAggregationResultList, InstanceSort
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- NodeQueryStep,
- EdgeQueryStep,
- DataClassQueryBuilder,
-)
-from windmill.data_classes import (
- DomainModelCore,
- DomainModelWrite,
- ResourcesWriteResult,
- Windmill,
- WindmillWrite,
- WindmillFields,
- WindmillList,
- WindmillWriteList,
- WindmillTextFields,
- Blade,
- Metmast,
- Nacelle,
- Rotor,
-)
-from windmill.data_classes._windmill import (
- WindmillQuery,
- _WINDMILL_PROPERTIES_BY_FIELD,
- _create_windmill_filter,
-)
-from windmill._api._core import (
- DEFAULT_LIMIT_READ,
- Aggregations,
- NodeAPI,
- SequenceNotStr,
-)
-from windmill._api.windmill_blades import WindmillBladesAPI
-from windmill._api.windmill_metmast import WindmillMetmastAPI
-from windmill._api.windmill_query import WindmillQueryAPI
-
-
-class WindmillAPI(NodeAPI[Windmill, WindmillWrite, WindmillList, WindmillWriteList]):
- _view_id = dm.ViewId("power-models", "Windmill", "1")
- _properties_by_field = _WINDMILL_PROPERTIES_BY_FIELD
- _class_type = Windmill
- _class_list = WindmillList
- _class_write_list = WindmillWriteList
-
- def __init__(self, client: CogniteClient):
- super().__init__(client=client)
-
- self.blades_edge = WindmillBladesAPI(client)
- self.metmast_edge = WindmillMetmastAPI(client)
-
- def __call__(
- self,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- filter: dm.Filter | None = None,
- ) -> WindmillQueryAPI[WindmillList]:
- """Query starting at windmills.
-
- Args:
- min_capacity: The minimum value of the capacity to filter on.
- max_capacity: The maximum value of the capacity to filter on.
- nacelle: The nacelle to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- rotor: The rotor to filter on.
- windfarm: The windfarm to filter on.
- windfarm_prefix: The prefix of the windfarm to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of windmills to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- A query API for windmills.
-
- """
- has_data = dm.filters.HasData(views=[self._view_id])
- filter_ = _create_windmill_filter(
- self._view_id,
- min_capacity,
- max_capacity,
- nacelle,
- name,
- name_prefix,
- rotor,
- windfarm,
- windfarm_prefix,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- builder = DataClassQueryBuilder(WindmillList)
- return WindmillQueryAPI(self._client, builder, filter_, limit)
-
- def apply(
- self,
- windmill: WindmillWrite | Sequence[WindmillWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> ResourcesWriteResult:
- """Add or update (upsert) windmills.
-
- Note: This method iterates through all nodes and timeseries linked to windmill and creates them including the edges
- between the nodes. For example, if any of `blades`, `metmast`, `nacelle` or `rotor` are set, then these
- nodes as well as any nodes linked to them, and all the edges linking these nodes will be created.
-
- Args:
- windmill: Windmill or sequence of windmills to upsert.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method, will by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- Examples:
-
- Create a new windmill:
-
- >>> from windmill import WindmillClient
- >>> from windmill.data_classes import WindmillWrite
- >>> client = WindmillClient()
- >>> windmill = WindmillWrite(external_id="my_windmill", ...)
- >>> result = client.windmill.apply(windmill)
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the client instead. This means instead of "
- "`my_client.windmill.apply(my_items)` please use `my_client.upsert(my_items)`."
- "The motivation is that all apply methods are the same, and having one apply method per API "
- " class encourages users to create items in small batches, which is inefficient."
- "In addition, .upsert method is more descriptive of what the method does.",
- UserWarning,
- stacklevel=2,
- )
- return self._apply(windmill, replace, write_none)
-
- def delete(
- self, external_id: str | SequenceNotStr[str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> dm.InstancesDeleteResult:
- """Delete one or more windmill.
-
- Args:
- external_id: External id of the windmill to delete.
- space: The space where all the windmill are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete windmill by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.windmill.delete("my_windmill")
- """
- warnings.warn(
- "The .delete method is deprecated and will be removed in v1.0. "
- "Please use the .delete method on the client instead. This means instead of "
- "`my_client.windmill.delete(my_ids)` please use `my_client.delete(my_ids)`."
- "The motivation is that all delete methods are the same, and having one delete method per API "
- " class encourages users to delete items in small batches, which is inefficient.",
- UserWarning,
- stacklevel=2,
- )
- return self._delete(external_id, space)
-
- @overload
- def retrieve(
- self, external_id: str | dm.NodeId | tuple[str, str], space: str = DEFAULT_INSTANCE_SPACE
- ) -> Windmill | None: ...
-
- @overload
- def retrieve(
- self, external_id: SequenceNotStr[str | dm.NodeId | tuple[str, str]], space: str = DEFAULT_INSTANCE_SPACE
- ) -> WindmillList: ...
-
- def retrieve(
- self,
- external_id: str | dm.NodeId | tuple[str, str] | SequenceNotStr[str | dm.NodeId | tuple[str, str]],
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> Windmill | WindmillList | None:
- """Retrieve one or more windmills by id(s).
-
- Args:
- external_id: External id or list of external ids of the windmills.
- space: The space where all the windmills are located.
-
- Returns:
- The requested windmills.
-
- Examples:
-
- Retrieve windmill by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> windmill = client.windmill.retrieve("my_windmill")
-
- """
- return self._retrieve(
- external_id,
- space,
- retrieve_edges=True,
- edge_api_name_type_direction_view_id_penta=[
- (
- self.blades_edge,
- "blades",
- dm.DirectRelationReference("power-models", "Windmill.blades"),
- "outwards",
- dm.ViewId("power-models", "Blade", "1"),
- ),
- (
- self.metmast_edge,
- "metmast",
- dm.DirectRelationReference("power-models", "Windmill.metmast"),
- "outwards",
- dm.ViewId("power-models", "Metmast", "1"),
- ),
- ],
- )
-
- def search(
- self,
- query: str,
- properties: WindmillTextFields | SequenceNotStr[WindmillTextFields] | None = None,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: WindmillFields | SequenceNotStr[WindmillFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- ) -> WindmillList:
- """Search windmills
-
- Args:
- query: The search query,
- properties: The property to search, if nothing is passed all text fields will be searched.
- min_capacity: The minimum value of the capacity to filter on.
- max_capacity: The maximum value of the capacity to filter on.
- nacelle: The nacelle to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- rotor: The rotor to filter on.
- windfarm: The windfarm to filter on.
- windfarm_prefix: The prefix of the windfarm to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of windmills to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
-
- Returns:
- Search results windmills matching the query.
-
- Examples:
-
- Search for 'my_windmill' in all text properties:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> windmills = client.windmill.search('my_windmill')
-
- """
- filter_ = _create_windmill_filter(
- self._view_id,
- min_capacity,
- max_capacity,
- nacelle,
- name,
- name_prefix,
- rotor,
- windfarm,
- windfarm_prefix,
- external_id_prefix,
- space,
- filter,
- )
- return self._search(
- query=query,
- properties=properties,
- filter_=filter_,
- limit=limit,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- @overload
- def aggregate(
- self,
- aggregate: Aggregations | dm.aggregations.MetricAggregation,
- group_by: None = None,
- property: WindmillFields | SequenceNotStr[WindmillFields] | None = None,
- query: str | None = None,
- search_property: WindmillTextFields | SequenceNotStr[WindmillTextFields] | None = None,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.AggregatedNumberedValue: ...
-
- @overload
- def aggregate(
- self,
- aggregate: SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation],
- group_by: None = None,
- property: WindmillFields | SequenceNotStr[WindmillFields] | None = None,
- query: str | None = None,
- search_property: WindmillTextFields | SequenceNotStr[WindmillTextFields] | None = None,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> list[dm.aggregations.AggregatedNumberedValue]: ...
-
- @overload
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: WindmillFields | SequenceNotStr[WindmillFields],
- property: WindmillFields | SequenceNotStr[WindmillFields] | None = None,
- query: str | None = None,
- search_property: WindmillTextFields | SequenceNotStr[WindmillTextFields] | None = None,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> InstanceAggregationResultList: ...
-
- def aggregate(
- self,
- aggregate: (
- Aggregations
- | dm.aggregations.MetricAggregation
- | SequenceNotStr[Aggregations | dm.aggregations.MetricAggregation]
- ),
- group_by: WindmillFields | SequenceNotStr[WindmillFields] | None = None,
- property: WindmillFields | SequenceNotStr[WindmillFields] | None = None,
- query: str | None = None,
- search_property: WindmillTextFields | SequenceNotStr[WindmillTextFields] | None = None,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> (
- dm.aggregations.AggregatedNumberedValue
- | list[dm.aggregations.AggregatedNumberedValue]
- | InstanceAggregationResultList
- ):
- """Aggregate data across windmills
-
- Args:
- aggregate: The aggregation to perform.
- group_by: The property to group by when doing the aggregation.
- property: The property to perform aggregation on.
- query: The query to search for in the text field.
- search_property: The text field to search in.
- min_capacity: The minimum value of the capacity to filter on.
- max_capacity: The maximum value of the capacity to filter on.
- nacelle: The nacelle to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- rotor: The rotor to filter on.
- windfarm: The windfarm to filter on.
- windfarm_prefix: The prefix of the windfarm to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of windmills to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Aggregation results.
-
- Examples:
-
- Count windmills in space `my_space`:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> result = client.windmill.aggregate("count", space="my_space")
-
- """
-
- filter_ = _create_windmill_filter(
- self._view_id,
- min_capacity,
- max_capacity,
- nacelle,
- name,
- name_prefix,
- rotor,
- windfarm,
- windfarm_prefix,
- external_id_prefix,
- space,
- filter,
- )
- return self._aggregate(
- aggregate=aggregate,
- group_by=group_by, # type: ignore[arg-type]
- properties=property, # type: ignore[arg-type]
- query=query,
- search_properties=search_property, # type: ignore[arg-type]
- limit=limit,
- filter=filter_,
- )
-
- def histogram(
- self,
- property: WindmillFields,
- interval: float,
- query: str | None = None,
- search_property: WindmillTextFields | SequenceNotStr[WindmillTextFields] | None = None,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- ) -> dm.aggregations.HistogramValue:
- """Produces histograms for windmills
-
- Args:
- property: The property to use as the value in the histogram.
- interval: The interval to use for the histogram bins.
- query: The query to search for in the text field.
- search_property: The text field to search in.
- min_capacity: The minimum value of the capacity to filter on.
- max_capacity: The maximum value of the capacity to filter on.
- nacelle: The nacelle to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- rotor: The rotor to filter on.
- windfarm: The windfarm to filter on.
- windfarm_prefix: The prefix of the windfarm to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of windmills to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
-
- Returns:
- Bucketed histogram results.
-
- """
- filter_ = _create_windmill_filter(
- self._view_id,
- min_capacity,
- max_capacity,
- nacelle,
- name,
- name_prefix,
- rotor,
- windfarm,
- windfarm_prefix,
- external_id_prefix,
- space,
- filter,
- )
- return self._histogram(
- property,
- interval,
- query,
- search_property, # type: ignore[arg-type]
- limit,
- filter_,
- )
-
- def query(self) -> WindmillQuery:
- """Start a query for windmills."""
- warnings.warn("This method is renamed to .select", UserWarning, stacklevel=2)
- return WindmillQuery(self._client)
-
- def select(self) -> WindmillQuery:
- """Start selecting from windmills."""
- warnings.warn(
- "The .select is in alpha and is subject to breaking changes without notice.", UserWarning, stacklevel=2
- )
- return WindmillQuery(self._client)
-
- def list(
- self,
- min_capacity: float | None = None,
- max_capacity: float | None = None,
- nacelle: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- rotor: (
- str
- | tuple[str, str]
- | dm.NodeId
- | dm.DirectRelationReference
- | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference]
- | None
- ) = None,
- windfarm: str | list[str] | None = None,
- windfarm_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit: int = DEFAULT_LIMIT_READ,
- filter: dm.Filter | None = None,
- sort_by: WindmillFields | Sequence[WindmillFields] | None = None,
- direction: Literal["ascending", "descending"] = "ascending",
- sort: InstanceSort | list[InstanceSort] | None = None,
- retrieve_connections: Literal["skip", "identifier", "full"] = "skip",
- ) -> WindmillList:
- """List/filter windmills
-
- Args:
- min_capacity: The minimum value of the capacity to filter on.
- max_capacity: The maximum value of the capacity to filter on.
- nacelle: The nacelle to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- rotor: The rotor to filter on.
- windfarm: The windfarm to filter on.
- windfarm_prefix: The prefix of the windfarm to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of windmills to return. Defaults to 25. Set to -1, float("inf") or None to return all items.
- filter: (Advanced) If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- sort_by: The property to sort by.
- direction: The direction to sort by, either 'ascending' or 'descending'.
- sort: (Advanced) If sort_by and direction are not sufficient, you can write your own sorting.
- This will override the sort_by and direction. This allowos you to sort by multiple fields and
- specify the direction for each field as well as how to handle null values.
- retrieve_connections: Whether to retrieve `blades`, `metmast`, `nacelle` and `rotor` for the windmills. Defaults to 'skip'.
- 'skip' will not retrieve any connections, 'identifier' will only retrieve the identifier of the connected items, and 'full' will retrieve the full connected items.
-
- Returns:
- List of requested windmills
-
- Examples:
-
- List windmills and limit to 5:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> windmills = client.windmill.list(limit=5)
-
- """
- filter_ = _create_windmill_filter(
- self._view_id,
- min_capacity,
- max_capacity,
- nacelle,
- name,
- name_prefix,
- rotor,
- windfarm,
- windfarm_prefix,
- external_id_prefix,
- space,
- filter,
- )
-
- if retrieve_connections == "skip":
- return self._list(
- limit=limit,
- filter=filter_,
- sort_by=sort_by, # type: ignore[arg-type]
- direction=direction,
- sort=sort,
- )
-
- builder = DataClassQueryBuilder(WindmillList)
- has_data = dm.filters.HasData(views=[self._view_id])
- builder.append(
- NodeQueryStep(
- builder.create_name(None),
- dm.query.NodeResultSetExpression(
- filter=dm.filters.And(filter_, has_data) if filter_ else has_data,
- sort=self._create_sort(sort_by, direction, sort), # type: ignore[arg-type]
- ),
- Windmill,
- max_retrieve_limit=limit,
- raw_filter=filter_,
- )
- )
- from_root = builder.get_from()
- edge_blades = builder.create_name(from_root)
- builder.append(
- EdgeQueryStep(
- edge_blades,
- dm.query.EdgeResultSetExpression(
- from_=from_root,
- direction="outwards",
- chain_to="destination",
- ),
- )
- )
- edge_metmast = builder.create_name(from_root)
- builder.append(
- EdgeQueryStep(
- edge_metmast,
- dm.query.EdgeResultSetExpression(
- from_=from_root,
- direction="outwards",
- chain_to="destination",
- ),
- )
- )
- if retrieve_connections == "full":
- builder.append(
- NodeQueryStep(
- builder.create_name(edge_blades),
- dm.query.NodeResultSetExpression(
- from_=edge_blades,
- filter=dm.filters.HasData(views=[Blade._view_id]),
- ),
- Blade,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(edge_metmast),
- dm.query.NodeResultSetExpression(
- from_=edge_metmast,
- filter=dm.filters.HasData(views=[Metmast._view_id]),
- ),
- Metmast,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[Nacelle._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("nacelle"),
- ),
- Nacelle,
- )
- )
- builder.append(
- NodeQueryStep(
- builder.create_name(from_root),
- dm.query.NodeResultSetExpression(
- from_=from_root,
- filter=dm.filters.HasData(views=[Rotor._view_id]),
- direction="outwards",
- through=self._view_id.as_property_ref("rotor"),
- ),
- Rotor,
- )
- )
- # We know that that all nodes are connected as it is not possible to filter on connections
- builder.execute_query(self._client, remove_not_connected=False)
- return builder.unpack()
diff --git a/examples/windmill/_api/windmill_blades.py b/examples/windmill/_api/windmill_blades.py
deleted file mode 100644
index 5e1b8cea7..000000000
--- a/examples/windmill/_api/windmill_blades.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from __future__ import annotations
-
-
-from cognite.client import data_modeling as dm
-
-from windmill._api._core import DEFAULT_LIMIT_READ, EdgeAPI, _create_edge_filter
-from windmill.data_classes._core import DEFAULT_INSTANCE_SPACE
-
-
-class WindmillBladesAPI(EdgeAPI):
- def list(
- self,
- from_windmill: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- from_windmill_space: str = DEFAULT_INSTANCE_SPACE,
- to_blade: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- to_blade_space: str = DEFAULT_INSTANCE_SPACE,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit=DEFAULT_LIMIT_READ,
- ) -> dm.EdgeList:
- """List blade edges of a windmill.
-
- Args:
- from_windmill: ID of the source windmill.
- from_windmill_space: Location of the windmills.
- to_blade: ID of the target blade.
- to_blade_space: Location of the blades.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of blade edges to return. Defaults to 25. Set to -1, float("inf") or None
- to return all items.
-
- Returns:
- The requested blade edges.
-
- Examples:
-
- List 5 blade edges connected to "my_windmill":
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> windmill = client.windmill.blades_edge.list("my_windmill", limit=5)
-
- """
- filter_ = _create_edge_filter(
- dm.DirectRelationReference("power-models", "Windmill.blades"),
- from_windmill,
- from_windmill_space,
- to_blade,
- to_blade_space,
- external_id_prefix,
- space,
- )
- return self._list(filter_=filter_, limit=limit)
diff --git a/examples/windmill/_api/windmill_metmast.py b/examples/windmill/_api/windmill_metmast.py
deleted file mode 100644
index 4f4a8593a..000000000
--- a/examples/windmill/_api/windmill_metmast.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from __future__ import annotations
-
-
-from cognite.client import data_modeling as dm
-
-from windmill._api._core import DEFAULT_LIMIT_READ, EdgeAPI, _create_edge_filter
-from windmill.data_classes._core import DEFAULT_INSTANCE_SPACE
-
-
-class WindmillMetmastAPI(EdgeAPI):
- def list(
- self,
- from_windmill: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- from_windmill_space: str = DEFAULT_INSTANCE_SPACE,
- to_metmast: str | list[str] | dm.NodeId | list[dm.NodeId] | None = None,
- to_metmast_space: str = DEFAULT_INSTANCE_SPACE,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- limit=DEFAULT_LIMIT_READ,
- ) -> dm.EdgeList:
- """List metmast edges of a windmill.
-
- Args:
- from_windmill: ID of the source windmill.
- from_windmill_space: Location of the windmills.
- to_metmast: ID of the target metmast.
- to_metmast_space: Location of the metmasts.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- limit: Maximum number of metmast edges to return. Defaults to 25. Set to -1, float("inf") or None
- to return all items.
-
- Returns:
- The requested metmast edges.
-
- Examples:
-
- List 5 metmast edges connected to "my_windmill":
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> windmill = client.windmill.metmast_edge.list("my_windmill", limit=5)
-
- """
- filter_ = _create_edge_filter(
- dm.DirectRelationReference("power-models", "Windmill.metmast"),
- from_windmill,
- from_windmill_space,
- to_metmast,
- to_metmast_space,
- external_id_prefix,
- space,
- )
- return self._list(filter_=filter_, limit=limit)
diff --git a/examples/windmill/_api/windmill_query.py b/examples/windmill/_api/windmill_query.py
deleted file mode 100644
index 6e4bc84ec..000000000
--- a/examples/windmill/_api/windmill_query.py
+++ /dev/null
@@ -1,249 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, cast
-
-from cognite.client import data_modeling as dm, CogniteClient
-
-from windmill.data_classes import (
- DomainModelCore,
- Windmill,
- Nacelle,
- Rotor,
-)
-from windmill.data_classes._blade import (
- Blade,
- _create_blade_filter,
-)
-from windmill.data_classes._metmast import (
- Metmast,
- _create_metmast_filter,
-)
-from windmill._api._core import (
- DEFAULT_QUERY_LIMIT,
- EdgeQueryStep,
- NodeQueryStep,
- DataClassQueryBuilder,
- QueryAPI,
- T_DomainModelList,
- _create_edge_filter,
-)
-
-if TYPE_CHECKING:
- from windmill._api.blade_query import BladeQueryAPI
- from windmill._api.metmast_query import MetmastQueryAPI
-
-
-class WindmillQueryAPI(QueryAPI[T_DomainModelList]):
- _view_id = dm.ViewId("power-models", "Windmill", "1")
-
- def __init__(
- self,
- client: CogniteClient,
- builder: DataClassQueryBuilder[T_DomainModelList],
- filter_: dm.filters.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- ):
- super().__init__(client, builder)
- from_ = self._builder.get_from()
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- filter=filter_,
- ),
- result_cls=Windmill,
- max_retrieve_limit=limit,
- )
- )
-
- def blades(
- self,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- external_id_prefix_edge: str | None = None,
- space_edge: str | list[str] | None = None,
- filter: dm.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- retrieve_nacelle: bool = False,
- retrieve_rotor: bool = False,
- ) -> BladeQueryAPI[T_DomainModelList]:
- """Query along the blade edges of the windmill.
-
- Args:
- is_damaged: The is damaged to filter on.
- name: The name to filter on.
- name_prefix: The prefix of the name to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- external_id_prefix_edge: The prefix of the external ID to filter on.
- space_edge: The space to filter on.
- filter: (Advanced) Filter applied to node. If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- limit: Maximum number of blade edges to return. Defaults to 3. Set to -1, float("inf") or None
- to return all items.
- retrieve_nacelle: Whether to retrieve the nacelle for each windmill or not.
- retrieve_rotor: Whether to retrieve the rotor for each windmill or not.
-
- Returns:
- BladeQueryAPI: The query API for the blade.
- """
- from .blade_query import BladeQueryAPI
-
- # from is a string as we added a node query step in the __init__ method
- from_ = cast(str, self._builder.get_from())
- edge_filter = _create_edge_filter(
- dm.DirectRelationReference("power-models", "Windmill.blades"),
- external_id_prefix=external_id_prefix_edge,
- space=space_edge,
- )
- self._builder.append(
- EdgeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.EdgeResultSetExpression(
- filter=edge_filter,
- from_=from_,
- direction="outwards",
- ),
- max_retrieve_limit=limit,
- )
- )
-
- view_id = BladeQueryAPI._view_id
- has_data = dm.filters.HasData(views=[view_id])
- node_filer = _create_blade_filter(
- view_id,
- is_damaged,
- name,
- name_prefix,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- if retrieve_nacelle:
- self._query_append_nacelle(from_)
- if retrieve_rotor:
- self._query_append_rotor(from_)
- return BladeQueryAPI(self._client, self._builder, node_filer, limit)
-
- def metmast(
- self,
- min_position: float | None = None,
- max_position: float | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- external_id_prefix_edge: str | None = None,
- space_edge: str | list[str] | None = None,
- filter: dm.Filter | None = None,
- limit: int = DEFAULT_QUERY_LIMIT,
- retrieve_nacelle: bool = False,
- retrieve_rotor: bool = False,
- ) -> MetmastQueryAPI[T_DomainModelList]:
- """Query along the metmast edges of the windmill.
-
- Args:
- min_position: The minimum value of the position to filter on.
- max_position: The maximum value of the position to filter on.
- external_id_prefix: The prefix of the external ID to filter on.
- space: The space to filter on.
- external_id_prefix_edge: The prefix of the external ID to filter on.
- space_edge: The space to filter on.
- filter: (Advanced) Filter applied to node. If the filtering available in the above is not sufficient, you can write your own filtering which will be ANDed with the filter above.
- limit: Maximum number of metmast edges to return. Defaults to 3. Set to -1, float("inf") or None
- to return all items.
- retrieve_nacelle: Whether to retrieve the nacelle for each windmill or not.
- retrieve_rotor: Whether to retrieve the rotor for each windmill or not.
-
- Returns:
- MetmastQueryAPI: The query API for the metmast.
- """
- from .metmast_query import MetmastQueryAPI
-
- # from is a string as we added a node query step in the __init__ method
- from_ = cast(str, self._builder.get_from())
- edge_filter = _create_edge_filter(
- dm.DirectRelationReference("power-models", "Windmill.metmast"),
- external_id_prefix=external_id_prefix_edge,
- space=space_edge,
- )
- self._builder.append(
- EdgeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.EdgeResultSetExpression(
- filter=edge_filter,
- from_=from_,
- direction="outwards",
- ),
- max_retrieve_limit=limit,
- )
- )
-
- view_id = MetmastQueryAPI._view_id
- has_data = dm.filters.HasData(views=[view_id])
- node_filer = _create_metmast_filter(
- view_id,
- min_position,
- max_position,
- external_id_prefix,
- space,
- (filter and dm.filters.And(filter, has_data)) or has_data,
- )
- if retrieve_nacelle:
- self._query_append_nacelle(from_)
- if retrieve_rotor:
- self._query_append_rotor(from_)
- return MetmastQueryAPI(self._client, self._builder, node_filer, limit)
-
- def query(
- self,
- retrieve_nacelle: bool = False,
- retrieve_rotor: bool = False,
- ) -> T_DomainModelList:
- """Execute query and return the result.
-
- Args:
- retrieve_nacelle: Whether to retrieve the nacelle for each windmill or not.
- retrieve_rotor: Whether to retrieve the rotor for each windmill or not.
-
- Returns:
- The list of the source nodes of the query.
-
- """
- from_ = self._builder[-1].name
- if retrieve_nacelle:
- self._query_append_nacelle(from_)
- if retrieve_rotor:
- self._query_append_rotor(from_)
- return self._query()
-
- def _query_append_nacelle(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("nacelle"),
- direction="outwards",
- filter=dm.filters.HasData(views=[Nacelle._view_id]),
- ),
- result_cls=Nacelle,
- ),
- )
-
- def _query_append_rotor(self, from_: str) -> None:
- self._builder.append(
- NodeQueryStep(
- name=self._builder.create_name(from_),
- expression=dm.query.NodeResultSetExpression(
- from_=from_,
- through=self._view_id.as_property_ref("rotor"),
- direction="outwards",
- filter=dm.filters.HasData(views=[Rotor._view_id]),
- ),
- result_cls=Rotor,
- ),
- )
diff --git a/examples/windmill/_api_client.py b/examples/windmill/_api_client.py
deleted file mode 100644
index 350a22866..000000000
--- a/examples/windmill/_api_client.py
+++ /dev/null
@@ -1,276 +0,0 @@
-from __future__ import annotations
-
-import warnings
-from pathlib import Path
-from typing import Any, Sequence
-
-from cognite.client import ClientConfig, CogniteClient, data_modeling as dm
-from cognite.client.data_classes import TimeSeriesList, FileMetadataList, SequenceList
-from cognite.client.credentials import OAuthClientCredentials
-
-from windmill._api import (
- BladeAPI,
- GearboxAPI,
- GeneratorAPI,
- HighSpeedShaftAPI,
- MainShaftAPI,
- MetmastAPI,
- NacelleAPI,
- PowerInverterAPI,
- RotorAPI,
- SensorPositionAPI,
- WindmillAPI,
-)
-from windmill._api._core import SequenceNotStr, GraphQLQueryResponse
-from windmill.data_classes._core import DEFAULT_INSTANCE_SPACE, GraphQLList
-from windmill import data_classes
-
-
-class WindmillClient:
- """
- WindmillClient
-
- Generated with:
- pygen = 0.99.49
- cognite-sdk = 7.66.0
- pydantic = 2.9.2
-
- Data Model:
- space: power-models
- externalId: Windmill
- version: 1
- """
-
- def __init__(self, config_or_client: CogniteClient | ClientConfig):
- if isinstance(config_or_client, CogniteClient):
- client = config_or_client
- elif isinstance(config_or_client, ClientConfig):
- client = CogniteClient(config_or_client)
- else:
- raise ValueError(f"Expected CogniteClient or ClientConfig, got {type(config_or_client)}")
- # The client name is used for aggregated logging of Pygen Usage
- client.config.client_name = "CognitePygen:0.99.49"
-
- self._client = client
-
- self.blade = BladeAPI(client)
- self.gearbox = GearboxAPI(client)
- self.generator = GeneratorAPI(client)
- self.high_speed_shaft = HighSpeedShaftAPI(client)
- self.main_shaft = MainShaftAPI(client)
- self.metmast = MetmastAPI(client)
- self.nacelle = NacelleAPI(client)
- self.power_inverter = PowerInverterAPI(client)
- self.rotor = RotorAPI(client)
- self.sensor_position = SensorPositionAPI(client)
- self.windmill = WindmillAPI(client)
-
- def upsert(
- self,
- items: data_classes.DomainModelWrite | Sequence[data_classes.DomainModelWrite],
- replace: bool = False,
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> data_classes.ResourcesWriteResult:
- """Add or update (upsert) items.
-
- This method will create the nodes, edges, timeseries, files and sequences of the supplied items.
-
- Args:
- items: One or more instances of the pygen generated data classes.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method will, by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- allow_version_increase (bool): If set to true, the version of the instance will be increased if the instance already exists.
- If you get an error: 'A version conflict caused the ingest to fail', you can set this to true to allow
- the version to increase.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- """
- instances = self._create_instances(items, write_none, allow_version_increase)
- result = self._client.data_modeling.instances.apply(
- nodes=instances.nodes,
- edges=instances.edges,
- auto_create_start_nodes=True,
- auto_create_end_nodes=True,
- replace=replace,
- )
- time_series = TimeSeriesList([])
- if instances.time_series:
- time_series = self._client.time_series.upsert(instances.time_series, mode="patch")
- files = FileMetadataList([])
- if instances.files:
- for file in instances.files:
- created, _ = self._client.files.create(file, overwrite=True)
- files.append(created)
-
- sequences = SequenceList([])
- if instances.sequences:
- sequences = self._client.sequences.upsert(instances.sequences, mode="patch")
-
- return data_classes.ResourcesWriteResult(result.nodes, result.edges, time_series, files, sequences)
-
- def _create_instances(
- self,
- items: data_classes.DomainModelWrite | Sequence[data_classes.DomainModelWrite],
- write_none: bool,
- allow_version_increase: bool,
- ) -> data_classes.ResourcesWrite:
- if isinstance(items, data_classes.DomainModelWrite):
- instances = items.to_instances_write(write_none, allow_version_increase)
- else:
- instances = data_classes.ResourcesWrite()
- cache: set[tuple[str, str]] = set()
- for item in items:
- instances.extend(
- item._to_instances_write(
- cache,
- write_none,
- allow_version_increase,
- )
- )
- return instances
-
- def apply(
- self,
- items: data_classes.DomainModelWrite | Sequence[data_classes.DomainModelWrite],
- replace: bool = False,
- write_none: bool = False,
- ) -> data_classes.ResourcesWriteResult:
- """[DEPRECATED] Add or update (upsert) items.
-
- Args:
- items: One or more instances of the pygen generated data classes.
- replace (bool): How do we behave when a property value exists? Do we replace all matching and existing values with the supplied values (true)?
- Or should we merge in new values for properties together with the existing values (false)? Note: This setting applies for all nodes or edges specified in the ingestion call.
- write_none (bool): This method will, by default, skip properties that are set to None. However, if you want to set properties to None,
- you can set this parameter to True. Note this only applies to properties that are nullable.
- Returns:
- Created instance(s), i.e., nodes, edges, and time series.
-
- """
- warnings.warn(
- "The .apply method is deprecated and will be removed in v1.0. "
- "Please use the .upsert method on the instead."
- "The motivation is that .upsert is a more descriptive name for the operation.",
- UserWarning,
- stacklevel=2,
- )
- return self.upsert(items, replace, write_none)
-
- def delete(
- self,
- external_id: (
- str
- | dm.NodeId
- | data_classes.DomainModelWrite
- | SequenceNotStr[str | dm.NodeId | data_classes.DomainModelWrite]
- ),
- space: str = DEFAULT_INSTANCE_SPACE,
- ) -> dm.InstancesDeleteResult:
- """Delete one or more items.
-
- If you pass in an item, it will be deleted recursively, i.e., all connected nodes and edges
- will be deleted as well.
-
- Args:
- external_id: The external id or items(s) to delete. Can also be a list of NodeId(s) or DomainModelWrite(s).
- space: The space where all the item(s) are located.
-
- Returns:
- The instance(s), i.e., nodes and edges which has been deleted. Empty list if nothing was deleted.
-
- Examples:
-
- Delete item by id:
-
- >>> from windmill import WindmillClient
- >>> client = WindmillClient()
- >>> client.delete("my_node_external_id")
- """
- if isinstance(external_id, str):
- return self._client.data_modeling.instances.delete(nodes=(space, external_id))
- elif isinstance(external_id, dm.NodeId):
- return self._client.data_modeling.instances.delete(nodes=external_id)
- elif isinstance(external_id, data_classes.DomainModelWrite):
- resources = self._create_instances(external_id, False, False)
- return self._client.data_modeling.instances.delete(
- nodes=resources.nodes.as_ids(),
- edges=resources.edges.as_ids(),
- )
- elif isinstance(external_id, Sequence):
- node_ids: list[dm.NodeId] = []
- edge_ids: list[dm.EdgeId] = []
- for item in external_id:
- if isinstance(item, str):
- node_ids.append(dm.NodeId(space, item))
- elif isinstance(item, dm.NodeId):
- node_ids.append(item)
- elif isinstance(item, data_classes.DomainModelWrite):
- resources = self._create_instances(item, False, False)
- node_ids.extend(resources.nodes.as_ids())
- edge_ids.extend(resources.edges.as_ids())
- else:
- raise ValueError(
- f"Expected str, NodeId, or DomainModelWrite, Sequence of these types. Got {type(external_id)}"
- )
- return self._client.data_modeling.instances.delete(nodes=node_ids, edges=edge_ids)
- else:
- raise ValueError(
- f"Expected str, NodeId, or DomainModelWrite, Sequence of these types. Got {type(external_id)}"
- )
-
- def graphql_query(self, query: str, variables: dict[str, Any] | None = None) -> GraphQLList:
- """Execute a GraphQl query against the Windmill data model.
-
- Args:
- query (str): The GraphQL query to issue.
- variables (dict[str, Any] | None): An optional dict of variables to pass to the query.
- """
- data_model_id = dm.DataModelId("power-models", "Windmill", "1")
- result = self._client.data_modeling.graphql.query(data_model_id, query, variables)
- return GraphQLQueryResponse(data_model_id).parse(result)
-
- @classmethod
- def azure_project(
- cls, tenant_id: str, client_id: str, client_secret: str, cdf_cluster: str, project: str
- ) -> WindmillClient:
- credentials = OAuthClientCredentials.default_for_azure_ad(tenant_id, client_id, client_secret, cdf_cluster)
- config = ClientConfig.default(project, cdf_cluster, credentials)
-
- return cls(config)
-
- @classmethod
- def from_toml(cls, file_path: Path | str, section: str | None = "cognite") -> WindmillClient:
- import toml
-
- toml_content = toml.load(file_path)
- if section is not None:
- try:
- toml_content = toml_content[section]
- except KeyError as e:
- raise ValueError(f"Could not find section '{section}' in {file_path}") from e
-
- return cls.azure_project(**toml_content)
-
- def _repr_html_(self) -> str:
- return """WindmillClient generated from data model ("power-models", "Windmill", "1")
-with the following APIs available
- .blade
- .gearbox
- .generator
- .high_speed_shaft
- .main_shaft
- .metmast
- .nacelle
- .power_inverter
- .rotor
- .sensor_position
- .windmill
-
-and with the methods:
- .upsert - Create or update any instance.
- .delete - Delete instances.
-"""
diff --git a/examples/windmill/data_classes/__init__.py b/examples/windmill/data_classes/__init__.py
deleted file mode 100644
index b477eaefc..000000000
--- a/examples/windmill/data_classes/__init__.py
+++ /dev/null
@@ -1,305 +0,0 @@
-from windmill.data_classes._core import (
- DataRecord,
- DataRecordGraphQL,
- DataRecordWrite,
- DomainModel,
- DomainModelCore,
- DomainModelWrite,
- DomainModelList,
- DomainRelationWrite,
- GraphQLCore,
- GraphQLList,
- ResourcesWrite,
- ResourcesWriteResult,
- PageInfo,
- TimeSeriesGraphQL,
- FileMetadataGraphQL,
- SequenceColumnGraphQL,
- SequenceGraphQL,
-)
-from ._blade import (
- Blade,
- BladeApply,
- BladeApplyList,
- BladeFields,
- BladeGraphQL,
- BladeList,
- BladeTextFields,
- BladeWrite,
- BladeWriteList,
-)
-from ._gearbox import (
- Gearbox,
- GearboxApply,
- GearboxApplyList,
- GearboxFields,
- GearboxGraphQL,
- GearboxList,
- GearboxTextFields,
- GearboxWrite,
- GearboxWriteList,
-)
-from ._generator import (
- Generator,
- GeneratorApply,
- GeneratorApplyList,
- GeneratorFields,
- GeneratorGraphQL,
- GeneratorList,
- GeneratorTextFields,
- GeneratorWrite,
- GeneratorWriteList,
-)
-from ._high_speed_shaft import (
- HighSpeedShaft,
- HighSpeedShaftApply,
- HighSpeedShaftApplyList,
- HighSpeedShaftFields,
- HighSpeedShaftGraphQL,
- HighSpeedShaftList,
- HighSpeedShaftTextFields,
- HighSpeedShaftWrite,
- HighSpeedShaftWriteList,
-)
-from ._main_shaft import (
- MainShaft,
- MainShaftApply,
- MainShaftApplyList,
- MainShaftFields,
- MainShaftGraphQL,
- MainShaftList,
- MainShaftTextFields,
- MainShaftWrite,
- MainShaftWriteList,
-)
-from ._metmast import (
- Metmast,
- MetmastApply,
- MetmastApplyList,
- MetmastFields,
- MetmastGraphQL,
- MetmastList,
- MetmastTextFields,
- MetmastWrite,
- MetmastWriteList,
-)
-from ._nacelle import (
- Nacelle,
- NacelleApply,
- NacelleApplyList,
- NacelleFields,
- NacelleGraphQL,
- NacelleList,
- NacelleTextFields,
- NacelleWrite,
- NacelleWriteList,
-)
-from ._power_inverter import (
- PowerInverter,
- PowerInverterApply,
- PowerInverterApplyList,
- PowerInverterFields,
- PowerInverterGraphQL,
- PowerInverterList,
- PowerInverterTextFields,
- PowerInverterWrite,
- PowerInverterWriteList,
-)
-from ._rotor import (
- Rotor,
- RotorApply,
- RotorApplyList,
- RotorFields,
- RotorGraphQL,
- RotorList,
- RotorTextFields,
- RotorWrite,
- RotorWriteList,
-)
-from ._sensor_position import (
- SensorPosition,
- SensorPositionApply,
- SensorPositionApplyList,
- SensorPositionFields,
- SensorPositionGraphQL,
- SensorPositionList,
- SensorPositionTextFields,
- SensorPositionWrite,
- SensorPositionWriteList,
-)
-from ._windmill import (
- Windmill,
- WindmillApply,
- WindmillApplyList,
- WindmillFields,
- WindmillGraphQL,
- WindmillList,
- WindmillTextFields,
- WindmillWrite,
- WindmillWriteList,
-)
-
-Blade.model_rebuild()
-BladeGraphQL.model_rebuild()
-BladeWrite.model_rebuild()
-BladeApply.model_rebuild()
-Gearbox.model_rebuild()
-GearboxGraphQL.model_rebuild()
-GearboxWrite.model_rebuild()
-GearboxApply.model_rebuild()
-Generator.model_rebuild()
-GeneratorGraphQL.model_rebuild()
-GeneratorWrite.model_rebuild()
-GeneratorApply.model_rebuild()
-HighSpeedShaft.model_rebuild()
-HighSpeedShaftGraphQL.model_rebuild()
-HighSpeedShaftWrite.model_rebuild()
-HighSpeedShaftApply.model_rebuild()
-MainShaft.model_rebuild()
-MainShaftGraphQL.model_rebuild()
-MainShaftWrite.model_rebuild()
-MainShaftApply.model_rebuild()
-Metmast.model_rebuild()
-MetmastGraphQL.model_rebuild()
-MetmastWrite.model_rebuild()
-MetmastApply.model_rebuild()
-Nacelle.model_rebuild()
-NacelleGraphQL.model_rebuild()
-NacelleWrite.model_rebuild()
-NacelleApply.model_rebuild()
-PowerInverter.model_rebuild()
-PowerInverterGraphQL.model_rebuild()
-PowerInverterWrite.model_rebuild()
-PowerInverterApply.model_rebuild()
-Rotor.model_rebuild()
-RotorGraphQL.model_rebuild()
-RotorWrite.model_rebuild()
-RotorApply.model_rebuild()
-SensorPosition.model_rebuild()
-SensorPositionGraphQL.model_rebuild()
-SensorPositionWrite.model_rebuild()
-SensorPositionApply.model_rebuild()
-Windmill.model_rebuild()
-WindmillGraphQL.model_rebuild()
-WindmillWrite.model_rebuild()
-WindmillApply.model_rebuild()
-
-
-__all__ = [
- "DataRecord",
- "DataRecordGraphQL",
- "DataRecordWrite",
- "ResourcesWrite",
- "DomainModel",
- "DomainModelCore",
- "DomainModelWrite",
- "DomainModelList",
- "DomainRelationWrite",
- "GraphQLCore",
- "GraphQLList",
- "ResourcesWriteResult",
- "PageInfo",
- "TimeSeriesGraphQL",
- "FileMetadataGraphQL",
- "SequenceColumnGraphQL",
- "SequenceGraphQL",
- "Blade",
- "BladeGraphQL",
- "BladeWrite",
- "BladeApply",
- "BladeList",
- "BladeWriteList",
- "BladeApplyList",
- "BladeFields",
- "BladeTextFields",
- "Gearbox",
- "GearboxGraphQL",
- "GearboxWrite",
- "GearboxApply",
- "GearboxList",
- "GearboxWriteList",
- "GearboxApplyList",
- "GearboxFields",
- "GearboxTextFields",
- "Generator",
- "GeneratorGraphQL",
- "GeneratorWrite",
- "GeneratorApply",
- "GeneratorList",
- "GeneratorWriteList",
- "GeneratorApplyList",
- "GeneratorFields",
- "GeneratorTextFields",
- "HighSpeedShaft",
- "HighSpeedShaftGraphQL",
- "HighSpeedShaftWrite",
- "HighSpeedShaftApply",
- "HighSpeedShaftList",
- "HighSpeedShaftWriteList",
- "HighSpeedShaftApplyList",
- "HighSpeedShaftFields",
- "HighSpeedShaftTextFields",
- "MainShaft",
- "MainShaftGraphQL",
- "MainShaftWrite",
- "MainShaftApply",
- "MainShaftList",
- "MainShaftWriteList",
- "MainShaftApplyList",
- "MainShaftFields",
- "MainShaftTextFields",
- "Metmast",
- "MetmastGraphQL",
- "MetmastWrite",
- "MetmastApply",
- "MetmastList",
- "MetmastWriteList",
- "MetmastApplyList",
- "MetmastFields",
- "MetmastTextFields",
- "Nacelle",
- "NacelleGraphQL",
- "NacelleWrite",
- "NacelleApply",
- "NacelleList",
- "NacelleWriteList",
- "NacelleApplyList",
- "NacelleFields",
- "NacelleTextFields",
- "PowerInverter",
- "PowerInverterGraphQL",
- "PowerInverterWrite",
- "PowerInverterApply",
- "PowerInverterList",
- "PowerInverterWriteList",
- "PowerInverterApplyList",
- "PowerInverterFields",
- "PowerInverterTextFields",
- "Rotor",
- "RotorGraphQL",
- "RotorWrite",
- "RotorApply",
- "RotorList",
- "RotorWriteList",
- "RotorApplyList",
- "RotorFields",
- "RotorTextFields",
- "SensorPosition",
- "SensorPositionGraphQL",
- "SensorPositionWrite",
- "SensorPositionApply",
- "SensorPositionList",
- "SensorPositionWriteList",
- "SensorPositionApplyList",
- "SensorPositionFields",
- "SensorPositionTextFields",
- "Windmill",
- "WindmillGraphQL",
- "WindmillWrite",
- "WindmillApply",
- "WindmillList",
- "WindmillWriteList",
- "WindmillApplyList",
- "WindmillFields",
- "WindmillTextFields",
-]
diff --git a/examples/windmill/data_classes/_blade.py b/examples/windmill/data_classes/_blade.py
deleted file mode 100644
index c3b5aa821..000000000
--- a/examples/windmill/data_classes/_blade.py
+++ /dev/null
@@ -1,464 +0,0 @@
-from __future__ import annotations
-
-import warnings
-from collections.abc import Sequence
-from typing import TYPE_CHECKING, Any, ClassVar, Literal, no_type_check, Optional, Union
-
-from cognite.client import data_modeling as dm, CogniteClient
-from pydantic import Field
-from pydantic import field_validator, model_validator
-
-from windmill.data_classes._core import (
- DEFAULT_INSTANCE_SPACE,
- DEFAULT_QUERY_LIMIT,
- DataRecord,
- DataRecordGraphQL,
- DataRecordWrite,
- DomainModel,
- DomainModelWrite,
- DomainModelWriteList,
- DomainModelList,
- DomainRelation,
- DomainRelationWrite,
- GraphQLCore,
- ResourcesWrite,
- T_DomainModelList,
- as_direct_relation_reference,
- as_instance_dict_id,
- as_node_id,
- as_pygen_node_id,
- are_nodes_equal,
- is_tuple_id,
- select_best_node,
- QueryCore,
- NodeQueryCore,
- StringFilter,
- BooleanFilter,
-)
-
-if TYPE_CHECKING:
- from windmill.data_classes._sensor_position import (
- SensorPosition,
- SensorPositionList,
- SensorPositionGraphQL,
- SensorPositionWrite,
- SensorPositionWriteList,
- )
-
-
-__all__ = [
- "Blade",
- "BladeWrite",
- "BladeApply",
- "BladeList",
- "BladeWriteList",
- "BladeApplyList",
- "BladeFields",
- "BladeTextFields",
- "BladeGraphQL",
-]
-
-
-BladeTextFields = Literal["external_id", "name"]
-BladeFields = Literal["external_id", "is_damaged", "name"]
-
-_BLADE_PROPERTIES_BY_FIELD = {
- "external_id": "externalId",
- "is_damaged": "is_damaged",
- "name": "name",
-}
-
-
-class BladeGraphQL(GraphQLCore):
- """This represents the reading version of blade, used
- when data is retrieved from CDF using GraphQL.
-
- It is used when retrieving data from CDF using GraphQL.
-
- Args:
- space: The space where the node is located.
- external_id: The external id of the blade.
- data_record: The data record of the blade node.
- is_damaged: The is damaged field.
- name: The name field.
- sensor_positions: The sensor position field.
- """
-
- view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Blade", "1")
- is_damaged: Optional[bool] = None
- name: Optional[str] = None
- sensor_positions: Optional[list[SensorPositionGraphQL]] = Field(default=None, repr=False)
-
- @model_validator(mode="before")
- def parse_data_record(cls, values: Any) -> Any:
- if not isinstance(values, dict):
- return values
- if "lastUpdatedTime" in values or "createdTime" in values:
- values["dataRecord"] = DataRecordGraphQL(
- created_time=values.pop("createdTime", None),
- last_updated_time=values.pop("lastUpdatedTime", None),
- )
- return values
-
- @field_validator("sensor_positions", mode="before")
- def parse_graphql(cls, value: Any) -> Any:
- if not isinstance(value, dict):
- return value
- if "items" in value:
- return value["items"]
- return value
-
- # We do the ignore argument type as we let pydantic handle the type checking
- @no_type_check
- def as_read(self) -> Blade:
- """Convert this GraphQL format of blade to the reading format."""
- if self.data_record is None:
- raise ValueError("This object cannot be converted to a read format because it lacks a data record.")
- return Blade(
- space=self.space,
- external_id=self.external_id,
- data_record=DataRecord(
- version=0,
- last_updated_time=self.data_record.last_updated_time,
- created_time=self.data_record.created_time,
- ),
- is_damaged=self.is_damaged,
- name=self.name,
- sensor_positions=[sensor_position.as_read() for sensor_position in self.sensor_positions or []],
- )
-
- # We do the ignore argument type as we let pydantic handle the type checking
- @no_type_check
- def as_write(self) -> BladeWrite:
- """Convert this GraphQL format of blade to the writing format."""
- return BladeWrite(
- space=self.space,
- external_id=self.external_id,
- data_record=DataRecordWrite(existing_version=0),
- is_damaged=self.is_damaged,
- name=self.name,
- sensor_positions=[sensor_position.as_write() for sensor_position in self.sensor_positions or []],
- )
-
-
-class Blade(DomainModel):
- """This represents the reading version of blade.
-
- It is used to when data is retrieved from CDF.
-
- Args:
- space: The space where the node is located.
- external_id: The external id of the blade.
- data_record: The data record of the blade node.
- is_damaged: The is damaged field.
- name: The name field.
- sensor_positions: The sensor position field.
- """
-
- _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Blade", "1")
-
- space: str = DEFAULT_INSTANCE_SPACE
- node_type: Union[dm.DirectRelationReference, None] = None
- is_damaged: Optional[bool] = None
- name: Optional[str] = None
- sensor_positions: Optional[list[Union[SensorPosition, str, dm.NodeId]]] = Field(default=None, repr=False)
-
- def as_write(self) -> BladeWrite:
- """Convert this read version of blade to the writing version."""
- return BladeWrite(
- space=self.space,
- external_id=self.external_id,
- data_record=DataRecordWrite(existing_version=self.data_record.version),
- is_damaged=self.is_damaged,
- name=self.name,
- sensor_positions=[
- sensor_position.as_write() if isinstance(sensor_position, DomainModel) else sensor_position
- for sensor_position in self.sensor_positions or []
- ],
- )
-
- def as_apply(self) -> BladeWrite:
- """Convert this read version of blade to the writing version."""
- warnings.warn(
- "as_apply is deprecated and will be removed in v1.0. Use as_write instead.",
- UserWarning,
- stacklevel=2,
- )
- return self.as_write()
-
- @classmethod
- def _update_connections(
- cls,
- instances: dict[dm.NodeId | str, Blade], # type: ignore[override]
- nodes_by_id: dict[dm.NodeId | str, DomainModel],
- edges_by_source_node: dict[dm.NodeId, list[dm.Edge | DomainRelation]],
- ) -> None:
- from ._sensor_position import SensorPosition
-
- for instance in instances.values():
- if edges := edges_by_source_node.get(instance.as_id()):
- sensor_positions: list[SensorPosition | str | dm.NodeId] = []
- for edge in edges:
- value: DomainModel | DomainRelation | str | dm.NodeId
- if isinstance(edge, DomainRelation):
- value = edge
- else:
- other_end: dm.DirectRelationReference = (
- edge.end_node
- if edge.start_node.space == instance.space
- and edge.start_node.external_id == instance.external_id
- else edge.start_node
- )
- destination: dm.NodeId | str = (
- as_node_id(other_end)
- if other_end.space != DEFAULT_INSTANCE_SPACE
- else other_end.external_id
- )
- if destination in nodes_by_id:
- value = nodes_by_id[destination]
- else:
- value = destination
- edge_type = edge.edge_type if isinstance(edge, DomainRelation) else edge.type
-
- if edge_type == dm.DirectRelationReference("power-models", "Blade.sensor_positions") and isinstance(
- value, (SensorPosition, str, dm.NodeId)
- ):
- sensor_positions.append(value)
-
- instance.sensor_positions = sensor_positions or None
-
-
-class BladeWrite(DomainModelWrite):
- """This represents the writing version of blade.
-
- It is used to when data is sent to CDF.
-
- Args:
- space: The space where the node is located.
- external_id: The external id of the blade.
- data_record: The data record of the blade node.
- is_damaged: The is damaged field.
- name: The name field.
- sensor_positions: The sensor position field.
- """
-
- _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Blade", "1")
-
- space: str = DEFAULT_INSTANCE_SPACE
- node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None
- is_damaged: Optional[bool] = None
- name: Optional[str] = None
- sensor_positions: Optional[list[Union[SensorPositionWrite, str, dm.NodeId]]] = Field(default=None, repr=False)
-
- @field_validator("sensor_positions", mode="before")
- def as_node_id(cls, value: Any) -> Any:
- if isinstance(value, dm.DirectRelationReference):
- return dm.NodeId(value.space, value.external_id)
- elif isinstance(value, tuple) and len(value) == 2 and all(isinstance(item, str) for item in value):
- return dm.NodeId(value[0], value[1])
- elif isinstance(value, list):
- return [cls.as_node_id(item) for item in value]
- return value
-
- def _to_instances_write(
- self,
- cache: set[tuple[str, str]],
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> ResourcesWrite:
- resources = ResourcesWrite()
- if self.as_tuple_id() in cache:
- return resources
-
- properties: dict[str, Any] = {}
-
- if self.is_damaged is not None or write_none:
- properties["is_damaged"] = self.is_damaged
-
- if self.name is not None or write_none:
- properties["name"] = self.name
-
- if properties:
- this_node = dm.NodeApply(
- space=self.space,
- external_id=self.external_id,
- existing_version=None if allow_version_increase else self.data_record.existing_version,
- type=as_direct_relation_reference(self.node_type),
- sources=[
- dm.NodeOrEdgeData(
- source=self._view_id,
- properties=properties,
- )
- ],
- )
- resources.nodes.append(this_node)
- cache.add(self.as_tuple_id())
-
- edge_type = dm.DirectRelationReference("power-models", "Blade.sensor_positions")
- for sensor_position in self.sensor_positions or []:
- other_resources = DomainRelationWrite.from_edge_to_resources(
- cache,
- start_node=self,
- end_node=sensor_position,
- edge_type=edge_type,
- write_none=write_none,
- allow_version_increase=allow_version_increase,
- )
- resources.extend(other_resources)
-
- return resources
-
-
-class BladeApply(BladeWrite):
- def __new__(cls, *args, **kwargs) -> BladeApply:
- warnings.warn(
- "BladeApply is deprecated and will be removed in v1.0. Use BladeWrite instead."
- "The motivation for this change is that Write is a more descriptive name for the writing version of the"
- "Blade.",
- UserWarning,
- stacklevel=2,
- )
- return super().__new__(cls)
-
-
-class BladeList(DomainModelList[Blade]):
- """List of blades in the read version."""
-
- _INSTANCE = Blade
-
- def as_write(self) -> BladeWriteList:
- """Convert these read versions of blade to the writing versions."""
- return BladeWriteList([node.as_write() for node in self.data])
-
- def as_apply(self) -> BladeWriteList:
- """Convert these read versions of primitive nullable to the writing versions."""
- warnings.warn(
- "as_apply is deprecated and will be removed in v1.0. Use as_write instead.",
- UserWarning,
- stacklevel=2,
- )
- return self.as_write()
-
- @property
- def sensor_positions(self) -> SensorPositionList:
- from ._sensor_position import SensorPosition, SensorPositionList
-
- return SensorPositionList(
- [item for items in self.data for item in items.sensor_positions or [] if isinstance(item, SensorPosition)]
- )
-
-
-class BladeWriteList(DomainModelWriteList[BladeWrite]):
- """List of blades in the writing version."""
-
- _INSTANCE = BladeWrite
-
- @property
- def sensor_positions(self) -> SensorPositionWriteList:
- from ._sensor_position import SensorPositionWrite, SensorPositionWriteList
-
- return SensorPositionWriteList(
- [
- item
- for items in self.data
- for item in items.sensor_positions or []
- if isinstance(item, SensorPositionWrite)
- ]
- )
-
-
-class BladeApplyList(BladeWriteList): ...
-
-
-def _create_blade_filter(
- view_id: dm.ViewId,
- is_damaged: bool | None = None,
- name: str | list[str] | None = None,
- name_prefix: str | None = None,
- external_id_prefix: str | None = None,
- space: str | list[str] | None = None,
- filter: dm.Filter | None = None,
-) -> dm.Filter | None:
- filters: list[dm.Filter] = []
- if isinstance(is_damaged, bool):
- filters.append(dm.filters.Equals(view_id.as_property_ref("is_damaged"), value=is_damaged))
- if isinstance(name, str):
- filters.append(dm.filters.Equals(view_id.as_property_ref("name"), value=name))
- if name and isinstance(name, list):
- filters.append(dm.filters.In(view_id.as_property_ref("name"), values=name))
- if name_prefix is not None:
- filters.append(dm.filters.Prefix(view_id.as_property_ref("name"), value=name_prefix))
- if external_id_prefix is not None:
- filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix))
- if isinstance(space, str):
- filters.append(dm.filters.Equals(["node", "space"], value=space))
- if space and isinstance(space, list):
- filters.append(dm.filters.In(["node", "space"], values=space))
- if filter:
- filters.append(filter)
- return dm.filters.And(*filters) if filters else None
-
-
-class _BladeQuery(NodeQueryCore[T_DomainModelList, BladeList]):
- _view_id = Blade._view_id
- _result_cls = Blade
- _result_list_cls_end = BladeList
-
- def __init__(
- self,
- created_types: set[type],
- creation_path: list[QueryCore],
- client: CogniteClient,
- result_list_cls: type[T_DomainModelList],
- expression: dm.query.ResultSetExpression | None = None,
- connection_name: str | None = None,
- connection_type: Literal["reverse-list"] | None = None,
- reverse_expression: dm.query.ResultSetExpression | None = None,
- ):
- from ._sensor_position import _SensorPositionQuery
-
- super().__init__(
- created_types,
- creation_path,
- client,
- result_list_cls,
- expression,
- dm.filters.HasData(views=[self._view_id]),
- connection_name,
- connection_type,
- reverse_expression,
- )
-
- if _SensorPositionQuery not in created_types:
- self.sensor_positions = _SensorPositionQuery(
- created_types.copy(),
- self._creation_path,
- client,
- result_list_cls,
- dm.query.EdgeResultSetExpression(
- direction="outwards",
- chain_to="destination",
- ),
- connection_name="sensor_positions",
- )
-
- self.space = StringFilter(self, ["node", "space"])
- self.external_id = StringFilter(self, ["node", "externalId"])
- self.is_damaged = BooleanFilter(self, self._view_id.as_property_ref("is_damaged"))
- self.name = StringFilter(self, self._view_id.as_property_ref("name"))
- self._filter_classes.extend(
- [
- self.space,
- self.external_id,
- self.is_damaged,
- self.name,
- ]
- )
-
- def list_blade(self, limit: int = DEFAULT_QUERY_LIMIT) -> BladeList:
- return self._list(limit=limit)
-
-
-class BladeQuery(_BladeQuery[BladeList]):
- def __init__(self, client: CogniteClient):
- super().__init__(set(), [], client, BladeList)
diff --git a/examples/windmill/data_classes/_core/__init__.py b/examples/windmill/data_classes/_core/__init__.py
deleted file mode 100644
index ebd27f19c..000000000
--- a/examples/windmill/data_classes/_core/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from windmill.data_classes._core.constants import * # noqa
-from windmill.data_classes._core.base import * # noqa
-from windmill.data_classes._core.cdf_external import * # noqa
-from windmill.data_classes._core.helpers import * # noqa
-from windmill.data_classes._core.query import * # noqa
diff --git a/examples/windmill/data_classes/_core/base.py b/examples/windmill/data_classes/_core/base.py
deleted file mode 100644
index 137e3dcef..000000000
--- a/examples/windmill/data_classes/_core/base.py
+++ /dev/null
@@ -1,685 +0,0 @@
-from __future__ import annotations
-
-import datetime
-import sys
-import warnings
-from abc import ABC, abstractmethod
-from collections import UserList
-from collections.abc import Collection, Mapping
-from dataclasses import dataclass, field
-from typing import (
- Callable,
- cast,
- ClassVar,
- Generic,
- Optional,
- Any,
- Iterator,
- TypeVar,
- overload,
- Union,
- SupportsIndex,
-)
-
-import pandas as pd
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import (
- TimeSeriesWriteList,
- FileMetadataWriteList,
- SequenceWriteList,
- TimeSeriesList,
- FileMetadataList,
- SequenceList,
-)
-from cognite.client.data_classes.data_modeling.instances import (
- Instance,
- InstanceApply,
- Properties,
- PropertyValue,
-)
-from pydantic import BaseModel, Field, model_validator
-
-from windmill.data_classes._core.constants import DEFAULT_INSTANCE_SPACE
-
-if sys.version_info >= (3, 11):
- from typing import Self
-else:
- from typing_extensions import Self
-
-
-@dataclass
-class ResourcesWrite:
- nodes: dm.NodeApplyList = field(default_factory=lambda: dm.NodeApplyList([]))
- edges: dm.EdgeApplyList = field(default_factory=lambda: dm.EdgeApplyList([]))
- time_series: TimeSeriesWriteList = field(default_factory=lambda: TimeSeriesWriteList([]))
- files: FileMetadataWriteList = field(default_factory=lambda: FileMetadataWriteList([]))
- sequences: SequenceWriteList = field(default_factory=lambda: SequenceWriteList([]))
-
- def extend(self, other: ResourcesWrite) -> None:
- self.nodes.extend(other.nodes)
- self.edges.extend(other.edges)
- self.time_series.extend(other.time_series)
- self.files.extend(other.files)
- self.sequences.extend(other.sequences)
-
-
-@dataclass
-class ResourcesWriteResult:
- nodes: dm.NodeApplyResultList = field(default_factory=lambda: dm.NodeApplyResultList([]))
- edges: dm.EdgeApplyResultList = field(default_factory=lambda: dm.EdgeApplyResultList([]))
- time_series: TimeSeriesList = field(default_factory=lambda: TimeSeriesList([]))
- files: FileMetadataList = field(default_factory=lambda: FileMetadataList([]))
- sequences: SequenceList = field(default_factory=lambda: SequenceList([]))
-
-
-# Arbitrary types are allowed to be able to use the TimeSeries class
-class Core(BaseModel, arbitrary_types_allowed=True, populate_by_name=True):
- def to_pandas(self) -> pd.Series:
- return pd.Series(self.model_dump())
-
- def _repr_html_(self) -> str:
- """Returns HTML representation of DomainModel."""
- return self.to_pandas().to_frame("value")._repr_html_() # type: ignore[operator]
-
- def dump(self, by_alias: bool = True) -> dict[str, Any]:
- """Returns the item as a dictionary.
-
- Args:
- by_alias: Whether to use the alias names in the dictionary.
-
- Returns:
- The item as a dictionary.
-
- """
- return self.model_dump(by_alias=by_alias)
-
-
-T_Core = TypeVar("T_Core", bound=Core)
-
-
-class DataRecordGraphQL(Core):
- last_updated_time: Optional[datetime.datetime] = Field(None, alias="lastUpdatedTime")
- created_time: Optional[datetime.datetime] = Field(None, alias="createdTime")
-
-
-class GraphQLCore(Core, ABC):
- view_id: ClassVar[dm.ViewId]
- space: Optional[str] = None
- external_id: Optional[str] = Field(None, alias="externalId")
- data_record: Optional[DataRecordGraphQL] = Field(None, alias="dataRecord")
-
-
-class PageInfo(BaseModel):
- has_next_page: Optional[bool] = Field(None, alias="hasNextPage")
- has_previous_page: Optional[bool] = Field(None, alias="hasPreviousPage")
- start_cursor: Optional[str] = Field(None, alias="startCursor")
- end_cursor: Optional[str] = Field(None, alias="endCursor")
-
- @classmethod
- def load(cls, data: dict[str, Any]) -> PageInfo:
- return cls.model_validate(data)
-
-
-class GraphQLList(UserList):
- def __init__(self, nodes: Collection[GraphQLCore] | None = None):
- super().__init__(nodes or [])
- self.page_info: PageInfo | None = None
-
- # The dunder implementations are to get proper type hints
- def __iter__(self) -> Iterator[GraphQLCore]:
- return super().__iter__()
-
- @overload
- def __getitem__(self, item: SupportsIndex) -> GraphQLCore: ...
-
- @overload
- def __getitem__(self, item: slice) -> GraphQLList: ...
-
- def __getitem__(self, item: SupportsIndex | slice) -> GraphQLCore | GraphQLList:
- value = self.data[item]
- if isinstance(item, slice):
- return type(self)(value)
- return cast(GraphQLCore, value)
-
- def dump(self) -> list[dict[str, Any]]:
- return [node.model_dump() for node in self.data]
-
- def to_pandas(self, dropna_columns: bool = False) -> pd.DataFrame:
- """
- Convert the list of nodes to a pandas.DataFrame.
-
- Args:
- dropna_columns: Whether to drop columns that are all NaN.
-
- Returns:
- A pandas.DataFrame with the nodes as rows.
- """
- df = pd.DataFrame(self.dump())
- if df.empty:
- df = pd.DataFrame(columns=GraphQLCore.model_fields)
- # Reorder columns to have the most relevant first
- id_columns = ["space", "external_id"]
- end_columns = ["data_record"]
- fixed_columns = set(id_columns + end_columns)
- columns = (
- id_columns + [col for col in df if col not in fixed_columns] + [col for col in end_columns if col in df]
- )
- df = df[columns]
- if df.empty:
- return df
- if dropna_columns:
- df.dropna(how="all", axis=1, inplace=True)
- return df
-
- def _repr_html_(self) -> str:
- return self.to_pandas(dropna_columns=True)._repr_html_() # type: ignore[operator]
-
-
-class DomainModelCore(Core, ABC):
- _view_id: ClassVar[dm.ViewId]
-
- space: str
- external_id: str = Field(min_length=1, max_length=255, alias="externalId")
-
- def as_tuple_id(self) -> tuple[str, str]:
- return self.space, self.external_id
-
- def as_direct_reference(self) -> dm.DirectRelationReference:
- return dm.DirectRelationReference(space=self.space, external_id=self.external_id)
-
- @classmethod
- def _update_connections(
- cls,
- instances: dict[dm.NodeId | dm.EdgeId | str, Self],
- nodes_by_id: dict[dm.NodeId | str, DomainModel],
- edges_by_source_node: dict[dm.NodeId, list[dm.Edge | DomainRelation]],
- ) -> None:
- # This is used when unpacking a query result and should be overridden in the subclasses
- return None
-
-
-T_DomainModelCore = TypeVar("T_DomainModelCore", bound=DomainModelCore)
-
-
-class DataRecord(BaseModel):
- """The data record represents the metadata of a node.
-
- Args:
- created_time: The created time of the node.
- last_updated_time: The last updated time of the node.
- deleted_time: If present, the deleted time of the node.
- version: The version of the node.
- """
-
- version: int
- last_updated_time: datetime.datetime
- created_time: datetime.datetime
- deleted_time: Optional[datetime.datetime] = None
-
-
-class DomainModel(DomainModelCore, ABC):
- data_record: DataRecord
- node_type: Optional[dm.DirectRelationReference] = None
-
- def as_id(self) -> dm.NodeId:
- return dm.NodeId(space=self.space, external_id=self.external_id)
-
- @classmethod
- def from_instance(cls, instance: Instance) -> Self:
- data = instance.dump(camel_case=False)
- node_type = data.pop("type", None)
- space = data.pop("space")
- external_id = data.pop("external_id")
- return cls(
- space=space,
- external_id=external_id,
- data_record=DataRecord(**data),
- node_type=node_type,
- **unpack_properties(instance.properties),
- )
-
-
-T_DomainModel = TypeVar("T_DomainModel", bound=DomainModel)
-
-
-class DataRecordWrite(BaseModel):
- """The data record represents the metadata of a node.
-
- Args:
- existing_version: Fail the ingestion request if the node version is greater than or equal to this value.
- If no existingVersion is specified, the ingestion will always overwrite any existing data for the edge (for the specified container or instance).
- If existingVersion is set to 0, the upsert will behave as an insert, so it will fail the bulk if the item already exists.
- If skipOnVersionConflict is set on the ingestion request, then the item will be skipped instead of failing the ingestion request.
- """
-
- existing_version: Optional[int] = None
-
-
-T_DataRecord = TypeVar("T_DataRecord", bound=Union[DataRecord, DataRecordWrite])
-
-
-class _DataRecordListCore(UserList, Generic[T_DataRecord]):
- _INSTANCE: type[T_DataRecord]
-
- def __init__(self, nodes: Collection[T_DataRecord] | None = None):
- super().__init__(nodes or [])
-
- # The dunder implementations are to get proper type hints
- def __iter__(self) -> Iterator[T_DataRecord]:
- return super().__iter__()
-
- @overload
- def __getitem__(self, item: SupportsIndex) -> T_DataRecord: ...
-
- @overload
- def __getitem__(self, item: slice) -> _DataRecordListCore[T_DataRecord]: ...
-
- def __getitem__(self, item: SupportsIndex | slice) -> T_DataRecord | _DataRecordListCore[T_DataRecord]:
- value = self.data[item]
- if isinstance(item, slice):
- return type(self)(value)
- return cast(T_DataRecord, value)
-
- def to_pandas(self) -> pd.DataFrame:
- """
- Convert the list of nodes to a pandas.DataFrame.
-
- Returns:
- A pandas.DataFrame with the nodes as rows.
- """
- df = pd.DataFrame([item.model_dump() for item in self])
- if df.empty:
- df = pd.DataFrame(columns=self._INSTANCE.model_fields)
- return df
-
- def _repr_html_(self) -> str:
- return self.to_pandas()._repr_html_() # type: ignore[operator]
-
-
-class DataRecordList(_DataRecordListCore[DataRecord]):
- _INSTANCE = DataRecord
-
-
-class DataRecordWriteList(_DataRecordListCore[DataRecordWrite]):
- _INSTANCE = DataRecordWrite
-
-
-class DomainModelWrite(DomainModelCore, extra="ignore", populate_by_name=True):
- external_id_factory: ClassVar[Optional[Callable[[type[DomainModelWrite], dict], str]]] = None
- data_record: DataRecordWrite = Field(default_factory=DataRecordWrite)
- node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None
-
- def as_id(self) -> dm.NodeId:
- return dm.NodeId(space=self.space, external_id=self.external_id)
-
- def to_instances_write(
- self,
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> ResourcesWrite:
- return self._to_instances_write(set(), write_none, allow_version_increase)
-
- def to_instances_apply(self, write_none: bool = False) -> ResourcesWrite:
- warnings.warn(
- "to_instances_apply is deprecated and will be removed in v1.0. Use to_instances_write instead.",
- UserWarning,
- stacklevel=2,
- )
- return self.to_instances_write(write_none)
-
- @abstractmethod
- def _to_instances_write(
- self,
- cache: set[tuple[str, str]],
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> ResourcesWrite:
- raise NotImplementedError()
-
- @model_validator(mode="before")
- def create_external_id_if_factory(cls, data: Any) -> Any:
- if (
- isinstance(data, dict)
- and cls.external_id_factory is not None
- and data.get("external_id") is None
- and data.get("externalId") is None
- ):
- data["external_id"] = cls.external_id_factory(cls, data)
- return data
-
- @classmethod
- def from_instance(cls: type[T_DomainModelWrite], instance: InstanceApply) -> T_DomainModelWrite:
- data = instance.dump(camel_case=False)
- data.pop("instance_type", None)
- node_type = data.pop("type", None)
- space = data.pop("space")
- external_id = data.pop("external_id")
- sources = data.pop("sources", [])
- properties = {}
- for source in sources:
- for prop_name, prop_value in source["properties"].items():
- if isinstance(prop_value, dict) and "externalId" in prop_value and "space" in prop_value:
- if prop_value["space"] == DEFAULT_INSTANCE_SPACE:
- properties[prop_name] = prop_value["externalId"]
- else:
- properties[prop_name] = dm.NodeId(
- space=prop_value["space"], external_id=prop_value["externalId"]
- )
- else:
- properties[prop_name] = prop_value
- return cls(
- space=space, external_id=external_id, node_type=node_type, data_record=DataRecordWrite(**data), **properties
- )
-
-
-T_DomainModelWrite = TypeVar("T_DomainModelWrite", bound=DomainModelWrite)
-
-
-class CoreList(UserList, Generic[T_Core]):
- _INSTANCE: type[T_Core]
- _PARENT_CLASS: type[Core]
-
- def __init__(self, nodes: Collection[T_Core] | None = None):
- super().__init__(nodes or [])
-
- # The dunder implementations are to get proper type hints
- def __iter__(self) -> Iterator[T_Core]:
- return super().__iter__()
-
- @overload
- def __getitem__(self, item: SupportsIndex) -> T_Core: ...
-
- @overload
- def __getitem__(self, item: slice) -> Self: ...
-
- def __getitem__(self, item: SupportsIndex | slice) -> T_Core | Self:
- value = self.data[item]
- if isinstance(item, slice):
- return type(self)(value)
- return cast(T_Core, value)
-
- def dump(self) -> list[dict[str, Any]]:
- return [node.model_dump() for node in self.data]
-
- def as_external_ids(self) -> list[str]:
- return [node.external_id for node in self.data]
-
- def to_pandas(self, dropna_columns: bool = False) -> pd.DataFrame:
- """
- Convert the list of nodes to a pandas.DataFrame.
-
- Args:
- dropna_columns: Whether to drop columns that are all NaN.
-
- Returns:
- A pandas.DataFrame with the nodes as rows.
- """
- df = pd.DataFrame(self.dump())
- if df.empty:
- df = pd.DataFrame(columns=self._INSTANCE.model_fields)
- # Reorder columns to have the most relevant first
- id_columns = ["space", "external_id"]
- end_columns = ["node_type", "data_record"]
- fixed_columns = set(id_columns + end_columns)
- columns = (
- id_columns + [col for col in df if col not in fixed_columns] + [col for col in end_columns if col in df]
- )
- df = df[columns]
- if df.empty:
- return df
- if dropna_columns:
- df.dropna(how="all", axis=1, inplace=True)
- return df
-
- def _repr_html_(self) -> str:
- return self.to_pandas(dropna_columns=True)._repr_html_() # type: ignore[operator]
-
-
-class DomainModelList(CoreList[T_DomainModel]):
- _PARENT_CLASS = DomainModel
-
- @property
- def data_records(self) -> DataRecordList:
- return DataRecordList([node.data_record for node in self.data])
-
- def as_node_ids(self) -> list[dm.NodeId]:
- return [dm.NodeId(space=node.space, external_id=node.external_id) for node in self.data]
-
-
-T_DomainModelList = TypeVar("T_DomainModelList", bound=DomainModelList, covariant=True)
-
-
-class DomainModelWriteList(CoreList[T_DomainModelWrite]):
- _PARENT_CLASS = DomainModelWrite
-
- @property
- def data_records(self) -> DataRecordWriteList:
- return DataRecordWriteList([node.data_record for node in self])
-
- def as_node_ids(self) -> list[dm.NodeId]:
- return [dm.NodeId(space=node.space, external_id=node.external_id) for node in self]
-
- def to_instances_write(
- self,
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> ResourcesWrite:
- cache: set[tuple[str, str]] = set()
- domains = ResourcesWrite()
- for node in self:
- result = node._to_instances_write(cache, write_none, allow_version_increase)
- domains.extend(result)
- return domains
-
- def to_instances_apply(self, write_none: bool = False) -> ResourcesWrite:
- warnings.warn(
- "to_instances_apply is deprecated and will be removed in v1.0. Use to_instances_write instead.",
- UserWarning,
- stacklevel=2,
- )
- return self.to_instances_write(write_none)
-
-
-T_DomainModelWriteList = TypeVar("T_DomainModelWriteList", bound=DomainModelWriteList, covariant=True)
-
-
-class DomainRelation(DomainModelCore):
- edge_type: dm.DirectRelationReference
- start_node: dm.DirectRelationReference
- end_node: Any
- data_record: DataRecord
-
- def as_id(self) -> dm.EdgeId:
- return dm.EdgeId(space=self.space, external_id=self.external_id)
-
- @classmethod
- def from_instance(cls, instance: Instance) -> Self:
- data = instance.dump(camel_case=False)
- data.pop("instance_type", None)
- edge_type = data.pop("type", None)
- start_node = data.pop("start_node")
- end_node = data.pop("end_node")
- space = data.pop("space")
- external_id = data.pop("external_id")
- return cls(
- space=space,
- external_id=external_id,
- data_record=DataRecord(**data),
- edge_type=edge_type,
- start_node=start_node,
- end_node=end_node,
- **unpack_properties(instance.properties),
- )
-
-
-T_DomainRelation = TypeVar("T_DomainRelation", bound=DomainRelation)
-
-
-def default_edge_external_id_factory(
- start_node: DomainModelWrite | str | dm.NodeId,
- end_node: DomainModelWrite | str | dm.NodeId,
- edge_type: dm.DirectRelationReference,
-) -> str:
- start = start_node if isinstance(start_node, str) else start_node.external_id
- end = end_node if isinstance(end_node, str) else end_node.external_id
- return f"{start}:{end}"
-
-
-class DomainRelationWrite(Core, extra="forbid", populate_by_name=True):
- external_id_factory: ClassVar[
- Callable[
- [
- Union[DomainModelWrite, str, dm.NodeId],
- Union[DomainModelWrite, str, dm.NodeId],
- dm.DirectRelationReference,
- ],
- str,
- ]
- ] = default_edge_external_id_factory
- data_record: DataRecordWrite = Field(default_factory=DataRecordWrite)
- external_id: Optional[str] = Field(None, min_length=1, max_length=255)
-
- @abstractmethod
- def _to_instances_write(
- self,
- cache: set[tuple[str, str]],
- start_node: DomainModelWrite,
- edge_type: dm.DirectRelationReference,
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> ResourcesWrite:
- raise NotImplementedError()
-
- @classmethod
- def create_edge(
- cls,
- start_node: DomainModelWrite | str | dm.NodeId,
- end_node: DomainModelWrite | str | dm.NodeId,
- edge_type: dm.DirectRelationReference,
- ) -> dm.EdgeApply:
- if isinstance(start_node, (DomainModelWrite, dm.NodeId)):
- space = start_node.space
- elif isinstance(end_node, (DomainModelWrite, dm.NodeId)):
- space = end_node.space
- else:
- space = DEFAULT_INSTANCE_SPACE
-
- if isinstance(end_node, str):
- end_ref = dm.DirectRelationReference(space, end_node)
- elif isinstance(end_node, DomainModelWrite):
- end_ref = end_node.as_direct_reference()
- elif isinstance(end_node, dm.NodeId):
- end_ref = dm.DirectRelationReference(end_node.space, end_node.external_id)
- else:
- raise TypeError(f"Expected str or subclass of {DomainRelationWrite.__name__}, got {type(end_node)}")
-
- if isinstance(start_node, str):
- start_ref = dm.DirectRelationReference(space, start_node)
- elif isinstance(start_node, DomainModelWrite):
- start_ref = start_node.as_direct_reference()
- elif isinstance(start_node, dm.NodeId):
- start_ref = dm.DirectRelationReference(start_node.space, start_node.external_id)
- else:
- raise TypeError(f"Expected str or subclass of {DomainRelationWrite.__name__}, got {type(start_node)}")
-
- return dm.EdgeApply(
- space=space,
- external_id=cls.external_id_factory(start_node, end_node, edge_type),
- type=edge_type,
- start_node=start_ref,
- end_node=end_ref,
- )
-
- @classmethod
- def from_edge_to_resources(
- cls,
- cache: set[tuple[str, str]],
- start_node: DomainModelWrite | str | dm.NodeId,
- end_node: DomainModelWrite | str | dm.NodeId,
- edge_type: dm.DirectRelationReference,
- write_none: bool = False,
- allow_version_increase: bool = False,
- ) -> ResourcesWrite:
- resources = ResourcesWrite()
- edge = DomainRelationWrite.create_edge(start_node, end_node, edge_type)
- if (edge.space, edge.external_id) in cache:
- return resources
- resources.edges.append(edge)
- cache.add((edge.space, edge.external_id))
-
- if isinstance(end_node, DomainModelWrite):
- other_resources = end_node._to_instances_write(
- cache,
- write_none,
- allow_version_increase,
- )
- resources.extend(other_resources)
- if isinstance(start_node, DomainModelWrite):
- other_resources = start_node._to_instances_write(
- cache,
- write_none,
- allow_version_increase,
- )
- resources.extend(other_resources)
-
- return resources
-
- @classmethod
- def reset_external_id_factory(cls) -> None:
- cls.external_id_factory = default_edge_external_id_factory
-
-
-T_DomainRelationWrite = TypeVar("T_DomainRelationWrite", bound=DomainRelationWrite)
-
-
-class DomainRelationList(CoreList[T_DomainRelation]):
- _PARENT_CLASS = DomainRelation
-
- def as_edge_ids(self) -> list[dm.EdgeId]:
- return [edge.as_id() for edge in self.data]
-
- @property
- def data_records(self) -> DataRecordList:
- return DataRecordList([connection.data_record for connection in self.data])
-
-
-class DomainRelationWriteList(CoreList[T_DomainRelationWrite]):
- _PARENT_CLASS = DomainRelationWrite
-
- @property
- def data_records(self) -> DataRecordWriteList:
- return DataRecordWriteList([connection.data_record for connection in self.data])
-
- def as_edge_ids(self) -> list[dm.EdgeId]:
- return [edge.as_id() for edge in self.data]
-
-
-T_DomainRelationList = TypeVar("T_DomainRelationList", bound=DomainRelationList)
-
-
-def unpack_properties(properties: Properties) -> Mapping[str, PropertyValue | dm.NodeId]:
- unpacked: dict[str, PropertyValue | dm.NodeId] = {}
- for view_properties in properties.values():
- for prop_name, prop_value in view_properties.items():
- if isinstance(prop_value, dict) and "externalId" in prop_value and "space" in prop_value:
- if prop_value["space"] == DEFAULT_INSTANCE_SPACE:
- unpacked[prop_name] = prop_value["externalId"]
- else:
- unpacked[prop_name] = dm.NodeId(space=prop_value["space"], external_id=prop_value["externalId"])
- elif isinstance(prop_value, list):
- values: list[Any] = []
- for value in prop_value:
- if isinstance(value, dict) and "externalId" in value and "space" in value:
- if value["space"] == DEFAULT_INSTANCE_SPACE:
- values.append(value["externalId"])
- else:
- values.append(dm.NodeId(space=value["space"], external_id=value["externalId"]))
- else:
- values.append(value)
- unpacked[prop_name] = values
- else:
- unpacked[prop_name] = prop_value
- return unpacked
-
-
-T_DomainList = TypeVar("T_DomainList", bound=Union[DomainModelList, DomainRelationList], covariant=True)
diff --git a/examples/windmill/data_classes/_core/cdf_external.py b/examples/windmill/data_classes/_core/cdf_external.py
deleted file mode 100644
index 6712f57eb..000000000
--- a/examples/windmill/data_classes/_core/cdf_external.py
+++ /dev/null
@@ -1,299 +0,0 @@
-from __future__ import annotations
-
-import datetime
-from typing import (
- Annotated,
- Optional,
- Any,
- no_type_check,
-)
-
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes import Datapoints, SequenceColumnWrite, SequenceColumn
-from cognite.client.data_classes import (
- TimeSeries as CogniteTimeSeries,
- Sequence as CogniteSequence,
- FileMetadata as CogniteFileMetadata,
- TimeSeriesWrite as CogniteTimeSeriesWrite,
- SequenceWrite as CogniteSequenceWrite,
- FileMetadataWrite as CogniteFileMetadataWrite,
-)
-from cognite.client.data_classes.sequences import ValueType
-from cognite.client.utils import datetime_to_ms
-from pydantic import BaseModel, BeforeValidator, model_validator, field_validator
-from pydantic.alias_generators import to_camel
-from pydantic.functional_serializers import PlainSerializer
-
-
-TimeSeries = Annotated[
- CogniteTimeSeries,
- PlainSerializer(
- lambda v: v.dump(camel_case=True) if isinstance(v, CogniteTimeSeries) else v,
- return_type=dict,
- when_used="unless-none",
- ),
- BeforeValidator(lambda v: CogniteTimeSeries.load(v) if isinstance(v, dict) else v),
-]
-
-
-SequenceRead = Annotated[
- CogniteSequence,
- PlainSerializer(
- lambda v: v.dump(camel_case=True) if isinstance(v, CogniteSequence) else v,
- return_type=dict,
- when_used="unless-none",
- ),
- BeforeValidator(lambda v: CogniteSequence.load(v) if isinstance(v, dict) else v),
-]
-
-
-FileMetadata = Annotated[
- CogniteFileMetadata,
- PlainSerializer(
- lambda v: v.dump(camel_case=True) if isinstance(v, CogniteFileMetadata) else v,
- return_type=dict,
- when_used="unless-none",
- ),
- BeforeValidator(lambda v: CogniteFileMetadata.load(v) if isinstance(v, dict) else v),
-]
-
-
-TimeSeriesWrite = Annotated[
- CogniteTimeSeriesWrite,
- PlainSerializer(
- lambda v: v.dump(camel_case=True) if isinstance(v, CogniteTimeSeriesWrite) else v,
- return_type=dict,
- when_used="unless-none",
- ),
- BeforeValidator(lambda v: CogniteTimeSeriesWrite.load(v) if isinstance(v, dict) else v),
-]
-
-
-SequenceWrite = Annotated[
- CogniteSequenceWrite,
- PlainSerializer(
- lambda v: v.dump(camel_case=True) if isinstance(v, CogniteSequenceWrite) else v,
- return_type=dict,
- when_used="unless-none",
- ),
- BeforeValidator(lambda v: CogniteSequenceWrite.load(v) if isinstance(v, dict) else v),
-]
-
-FileMetadataWrite = Annotated[
- CogniteFileMetadataWrite,
- PlainSerializer(
- lambda v: v.dump(camel_case=True) if isinstance(v, CogniteFileMetadataWrite) else v,
- return_type=dict,
- when_used="unless-none",
- ),
- BeforeValidator(lambda v: CogniteFileMetadataWrite.load(v) if isinstance(v, dict) else v),
-]
-
-
-class GraphQLExternal(BaseModel, arbitrary_types_allowed=True, populate_by_name=True, alias_generator=to_camel): ...
-
-
-class TimeSeriesGraphQL(GraphQLExternal):
- id: Optional[int] = None
- external_id: Optional[str] = None
- instance_id: Optional[dm.NodeId] = None
- name: Optional[str] = None
- is_string: Optional[bool] = None
- metadata: Optional[dict[str, str]] = None
- unit: Optional[str] = None
- unit_external_id: Optional[str] = None
- asset_id: Optional[int] = None
- is_step: Optional[bool] = None
- description: Optional[str] = None
- security_categories: Optional[list[int]] = None
- data_set_id: Optional[int] = None
- created_time: Optional[int] = None
- last_updated_time: Optional[int] = None
- data: Optional[Datapoints] = None
-
- @model_validator(mode="before")
- def parse_datapoints(cls, data: Any) -> Any:
- if isinstance(data, dict) and "getDataPoints" in data:
- datapoints = data.pop("getDataPoints")
- if "items" in datapoints:
- for item in datapoints["items"]:
- # The Datapoints expects the timestamp to be in milliseconds
- item["timestamp"] = datetime_to_ms(
- datetime.datetime.fromisoformat(item["timestamp"].replace("Z", "+00:00"))
- )
- data["datapoints"] = datapoints["items"]
- data["data"] = Datapoints.load(data)
- return data
-
- def as_write(self) -> CogniteTimeSeriesWrite:
- return CogniteTimeSeriesWrite(
- external_id=self.external_id,
- name=self.name,
- is_string=self.is_string,
- metadata=self.metadata,
- unit=self.unit,
- unit_external_id=self.unit_external_id,
- asset_id=self.asset_id,
- is_step=self.is_step,
- description=self.description,
- )
-
- def as_read(self) -> CogniteTimeSeries:
- return CogniteTimeSeries(
- id=self.id,
- external_id=self.external_id,
- instance_id=self.instance_id,
- name=self.name,
- is_string=self.is_string,
- metadata=self.metadata,
- unit=self.unit,
- unit_external_id=self.unit_external_id,
- asset_id=self.asset_id,
- is_step=self.is_step,
- description=self.description,
- security_categories=self.security_categories,
- )
-
-
-class FileMetadataGraphQL(GraphQLExternal):
- external_id: Optional[str] = None
- name: Optional[str] = None
- source: Optional[str] = None
- mime_type: Optional[str] = None
- metadata: Optional[dict[str, str]] = None
- directory: Optional[str] = None
- asset_ids: Optional[list[int]] = None
- data_set_id: Optional[int] = None
- labels: Optional[list[dict]] = None
- geo_location: Optional[dict] = None
- source_created_time: Optional[int] = None
- source_modified_time: Optional[int] = None
- security_categories: Optional[list[int]] = None
- id: Optional[int] = None
- uploaded: Optional[bool] = None
- uploaded_time: Optional[int] = None
- created_time: Optional[int] = None
- last_updated_time: Optional[int] = None
-
- @no_type_check
- def as_write(self) -> CogniteFileMetadataWrite:
- return CogniteFileMetadataWrite(
- external_id=self.external_id,
- name=self.name,
- source=self.source,
- mime_type=self.mime_type,
- metadata=self.metadata,
- directory=self.directory,
- asset_ids=self.asset_ids,
- data_set_id=self.data_set_id,
- labels=self.labels,
- geo_location=self.geo_location,
- source_created_time=self.source_created_time,
- source_modified_time=self.source_modified_time,
- security_categories=self.security_categories,
- )
-
- @no_type_check
- def as_read(self) -> CogniteFileMetadata:
- return CogniteFileMetadata(
- external_id=self.external_id,
- name=self.name,
- source=self.source,
- mime_type=self.mime_type,
- metadata=self.metadata,
- directory=self.directory,
- asset_ids=self.asset_ids,
- data_set_id=self.data_set_id,
- labels=self.labels,
- geo_location=self.geo_location,
- source_created_time=self.source_created_time,
- source_modified_time=self.source_modified_time,
- security_categories=self.security_categories,
- id=self.id,
- uploaded=self.uploaded,
- uploaded_time=self.uploaded_time,
- created_time=self.created_time,
- last_updated_time=self.last_updated_time,
- )
-
-
-class SequenceColumnGraphQL(GraphQLExternal):
- external_id: Optional[str] = None
- name: Optional[str] = None
- description: Optional[str] = None
- value_type: Optional[ValueType] = None
- metadata: Optional[dict[str, str]] = None
- created_time: Optional[int] = None
- last_updated_time: Optional[int] = None
-
- @field_validator("value_type", mode="before")
- def title_value_type(cls, value: Any) -> Any:
- if isinstance(value, str):
- return value.title()
- return value
-
- @no_type_check
- def as_write(self) -> SequenceColumnWrite:
- if self.value_type is None:
- raise ValueError("value_type is required")
- return SequenceColumnWrite(
- external_id=self.external_id,
- name=self.name,
- description=self.description,
- value_type=self.value_type,
- metadata=self.metadata,
- )
-
- @no_type_check
- def as_read(self) -> SequenceColumn:
- if self.value_type is None:
- raise ValueError("value_type is required")
- return SequenceColumn(
- external_id=self.external_id,
- name=self.name,
- description=self.description,
- value_type=self.value_type,
- metadata=self.metadata,
- created_time=self.created_time,
- last_updated_time=self.last_updated_time,
- )
-
-
-class SequenceGraphQL(GraphQLExternal):
- id: Optional[int] = None
- name: Optional[str] = None
- description: Optional[str] = None
- asset_id: Optional[int] = None
- external_id: Optional[str] = None
- metadata: Optional[dict[str, str]] = None
- columns: Optional[list[SequenceColumnGraphQL]] = None
- created_time: Optional[int] = None
- last_updated_time: Optional[int] = None
- data_set_id: Optional[int] = None
-
- @no_type_check
- def as_write(self) -> CogniteSequenceWrite:
- return CogniteSequenceWrite(
- name=self.name,
- description=self.description,
- asset_id=self.asset_id,
- external_id=self.external_id,
- metadata=self.metadata,
- columns=[col.as_write() for col in self.columns or []] if self.columns else None,
- data_set_id=self.data_set_id,
- )
-
- @no_type_check
- def as_read(self) -> CogniteSequence:
- return CogniteSequence(
- id=self.id,
- name=self.name,
- description=self.description,
- asset_id=self.asset_id,
- external_id=self.external_id,
- metadata=self.metadata,
- columns=[col.as_read() for col in self.columns or []] if self.columns else None,
- created_time=self.created_time,
- last_updated_time=self.last_updated_time,
- data_set_id=self.data_set_id,
- )
diff --git a/examples/windmill/data_classes/_core/constants.py b/examples/windmill/data_classes/_core/constants.py
deleted file mode 100644
index 2cca8f6f1..000000000
--- a/examples/windmill/data_classes/_core/constants.py
+++ /dev/null
@@ -1,20 +0,0 @@
-DEFAULT_QUERY_LIMIT = 5
-INSTANCE_QUERY_LIMIT = 1_000
-# The limit used for the In filter in /search
-IN_FILTER_CHUNK_SIZE = 100
-# This is the actual limit of the API, we typically set it to a lower value to avoid hitting the limit.
-# The actual instance query limit is 10_000, but we set it to 5_000 such that is matches the In filter
-# which we use in /search for reverse of list direct relations.
-ACTUAL_INSTANCE_QUERY_LIMIT = 5_000
-DEFAULT_INSTANCE_SPACE = "windmill-instances"
-# The minimum estimated seconds before print progress on a query
-MINIMUM_ESTIMATED_SECONDS_BEFORE_PRINT_PROGRESS = 30
-PRINT_PROGRESS_PER_N_NODES = 10_000
-SEARCH_LIMIT = 1_000
-
-
-class _NotSetSentinel:
- """This is a special class that indicates that a value has not been set.
- It is used when we need to distinguish between not set and None."""
-
- ...
diff --git a/examples/windmill/data_classes/_core/helpers.py b/examples/windmill/data_classes/_core/helpers.py
deleted file mode 100644
index 66082a97a..000000000
--- a/examples/windmill/data_classes/_core/helpers.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from __future__ import annotations
-
-from typing import Any
-
-from cognite.client import data_modeling as dm
-from windmill.data_classes._core.base import DomainModel, T_DomainModel
-from windmill.data_classes._core.constants import DEFAULT_INSTANCE_SPACE
-
-
-def as_node_id(value: dm.DirectRelationReference) -> dm.NodeId:
- return dm.NodeId(space=value.space, external_id=value.external_id)
-
-
-def as_direct_relation_reference(
- value: dm.DirectRelationReference | dm.NodeId | tuple[str, str] | None
-) -> dm.DirectRelationReference | None:
- if value is None or isinstance(value, dm.DirectRelationReference):
- return value
- if isinstance(value, dm.NodeId):
- return dm.DirectRelationReference(space=value.space, external_id=value.external_id)
- if isinstance(value, tuple):
- return dm.DirectRelationReference(space=value[0], external_id=value[1])
- raise TypeError(f"Expected DirectRelationReference, NodeId or tuple, got {type(value)}")
-
-
-# Any is to make mypy happy, while the rest is a hint of what the function expects
-def as_instance_dict_id(value: str | dm.NodeId | tuple[str, str] | dm.DirectRelationReference | Any) -> dict[str, str]:
- if isinstance(value, str):
- return {"space": DEFAULT_INSTANCE_SPACE, "externalId": value}
- if isinstance(value, dm.NodeId):
- return {"space": value.space, "externalId": value.external_id}
- if isinstance(value, tuple) and is_tuple_id(value):
- return {"space": value[0], "externalId": value[1]}
- if isinstance(value, dm.DirectRelationReference):
- return {"space": value.space, "externalId": value.external_id}
- raise TypeError(f"Expected str, NodeId, tuple or DirectRelationReference, got {type(value)}")
-
-
-def is_tuple_id(value: Any) -> bool:
- return isinstance(value, tuple) and len(value) == 2 and isinstance(value[0], str) and isinstance(value[1], str)
-
-
-def as_pygen_node_id(value: DomainModel | dm.NodeId | str) -> dm.NodeId | str:
- if isinstance(value, str):
- return value
- elif value.space == DEFAULT_INSTANCE_SPACE:
- return value.external_id
- elif isinstance(value, dm.NodeId):
- return value
- return value.as_id()
-
-
-def are_nodes_equal(node1: DomainModel | str | dm.NodeId, node2: DomainModel | str | dm.NodeId) -> bool:
- if isinstance(node1, (str, dm.NodeId)):
- node1_id = node1
- else:
- node1_id = node1.as_id() if node1.space != DEFAULT_INSTANCE_SPACE else node1.external_id
- if isinstance(node2, (str, dm.NodeId)):
- node2_id = node2
- else:
- node2_id = node2.as_id() if node2.space != DEFAULT_INSTANCE_SPACE else node2.external_id
- return node1_id == node2_id
-
-
-def select_best_node(
- node1: T_DomainModel | str | dm.NodeId, node2: T_DomainModel | str | dm.NodeId
-) -> T_DomainModel | str | dm.NodeId:
- if isinstance(node1, DomainModel):
- return node1 # type: ignore[return-value]
- elif isinstance(node2, DomainModel):
- return node2 # type: ignore[return-value]
- else:
- return node1
diff --git a/examples/windmill/data_classes/_core/query.py b/examples/windmill/data_classes/_core/query.py
deleted file mode 100644
index 5de2853d8..000000000
--- a/examples/windmill/data_classes/_core/query.py
+++ /dev/null
@@ -1,963 +0,0 @@
-from __future__ import annotations
-
-import datetime
-import math
-import time
-import warnings
-from abc import ABC
-from collections import defaultdict
-from collections.abc import Collection, MutableSequence, Iterable, Sequence
-from contextlib import suppress
-from dataclasses import dataclass
-from typing import (
- cast,
- ClassVar,
- Generic,
- Any,
- Iterator,
- TypeVar,
- overload,
- Union,
- SupportsIndex,
- Literal,
-)
-
-from cognite.client import CogniteClient
-from cognite.client import data_modeling as dm
-from cognite.client.data_classes._base import CogniteObject
-from cognite.client.data_classes.aggregations import Count
-from cognite.client.data_classes.data_modeling.instances import Instance
-from cognite.client.exceptions import CogniteAPIError
-
-from windmill.data_classes._core.base import (
- DomainModelList,
- T_DomainList,
- DomainRelationList,
- DomainModelCore,
- T_DomainModelList,
- DomainRelation,
- DomainModel,
-)
-from windmill.data_classes._core.constants import (
- _NotSetSentinel,
- DEFAULT_QUERY_LIMIT,
- DEFAULT_INSTANCE_SPACE,
- ACTUAL_INSTANCE_QUERY_LIMIT,
- INSTANCE_QUERY_LIMIT,
- IN_FILTER_CHUNK_SIZE,
- MINIMUM_ESTIMATED_SECONDS_BEFORE_PRINT_PROGRESS,
- PRINT_PROGRESS_PER_N_NODES,
- SEARCH_LIMIT,
-)
-from windmill.data_classes._core.helpers import as_node_id
-
-
-T_DomainListEnd = TypeVar("T_DomainListEnd", bound=Union[DomainModelList, DomainRelationList], covariant=True)
-
-
-class QueryCore(Generic[T_DomainList, T_DomainListEnd]):
- _view_id: ClassVar[dm.ViewId]
- _result_list_cls_end: type[T_DomainListEnd]
- _result_cls: ClassVar[type[DomainModelCore]]
-
- def __init__(
- self,
- created_types: set[type],
- creation_path: "list[QueryCore]",
- client: CogniteClient,
- result_list_cls: type[T_DomainList],
- expression: dm.query.ResultSetExpression | None = None,
- view_filter: dm.filters.Filter | None = None,
- connection_name: str | None = None,
- connection_type: Literal["reverse-list"] | None = None,
- reverse_expression: dm.query.ResultSetExpression | None = None,
- ):
- created_types.add(type(self))
- self._creation_path = creation_path[:] + [self]
- self._client = client
- self._result_list_cls = result_list_cls
- self._view_filter = view_filter
- self._expression = expression or dm.query.NodeResultSetExpression()
- self._reverse_expression = reverse_expression
- self._connection_name = connection_name
- self._connection_type = connection_type
- self._filter_classes: list[Filtering] = []
-
- @property
- def _connection_names(self) -> set[str]:
- return {step._connection_name for step in self._creation_path if step._connection_name}
-
- @property
- def _is_reverseable(self) -> bool:
- return self._reverse_expression is not None
-
- def __getattr__(self, item: str) -> Any:
- if item in self._connection_names:
- nodes = [step._result_cls.__name__ for step in self._creation_path]
- raise ValueError(f"Circular reference detected. Cannot query a circular reference: {nodes}")
- elif self._connection_type == "reverse-list":
- raise ValueError(f"Cannot query across a reverse-list connection.")
- raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{item}'")
-
- def _assemble_filter(self) -> dm.filters.Filter | None:
- filters: list[dm.filters.Filter] = [self._view_filter] if self._view_filter else []
- for filter_cls in self._filter_classes:
- if item := filter_cls._as_filter():
- filters.append(item)
- return dm.filters.And(*filters) if filters else None
-
- def _repr_html_(self) -> str:
- nodes = [step._result_cls.__name__ for step in self._creation_path]
- edges = [step._connection_name or "missing" for step in self._creation_path[1:]]
- last_connection_name = self._connection_name or "missing"
- w = 120
- h = 40
- circles = " \n".join(f'
Call .list_full() to return a list of {nodes[0].title()} and -.list_{last_connection_name}() to return a list of {nodes[-1].title()}.
-""" - - -class NodeQueryCore(QueryCore[T_DomainModelList, T_DomainListEnd]): - _result_cls: ClassVar[type[DomainModel]] - - def list_full(self, limit: int = DEFAULT_QUERY_LIMIT) -> T_DomainModelList: - builder = self._create_query(limit, self._result_list_cls, return_step="first", try_reverse=True) - builder.execute_query(self._client, remove_not_connected=True) - return builder.unpack() - - def _list(self, limit: int = DEFAULT_QUERY_LIMIT) -> T_DomainListEnd: - builder = self._create_query(limit, cast(type[DomainModelList], self._result_list_cls_end), return_step="last") - for step in builder[:-1]: - step.select = None - builder.execute_query(self._client, remove_not_connected=False) - return builder.unpack() - - def _dump_yaml(self) -> str: - return self._create_query(DEFAULT_QUERY_LIMIT, self._result_list_cls)._dump_yaml() - - def _create_query( - self, - limit: int, - result_list_cls: type[DomainModelList], - return_step: Literal["first", "last"] | None = None, - try_reverse: bool = False, - ) -> DataClassQueryBuilder: - builder = DataClassQueryBuilder(result_list_cls, return_step=return_step) - from_: str | None = None - first: bool = True - is_last_reverse_list = False - for item in self._creation_path: - if is_last_reverse_list: - raise ValueError( - "Cannot traverse past reverse direct relation of list. " - "This is a limitation of the modeling implementation in your data model." - "To do this query, you need to reimplement the data model and use an edge to " - "implement this connection instead of a reverse direct relation" - ) - name = builder.create_name(from_) - max_retrieve_limit = limit if first else -1 - step: QueryStep - if isinstance(item, NodeQueryCore) and isinstance(item._expression, dm.query.NodeResultSetExpression): - step = NodeQueryStep( - name=name, - expression=item._expression, - result_cls=item._result_cls, - max_retrieve_limit=max_retrieve_limit, - connection_type=item._connection_type, - ) - step.expression.from_ = from_ - step.expression.filter = item._assemble_filter() - builder.append(step) - elif isinstance(item, NodeQueryCore) and isinstance(item._expression, dm.query.EdgeResultSetExpression): - edge_name = name - step = EdgeQueryStep(name=edge_name, expression=item._expression, max_retrieve_limit=max_retrieve_limit) - step.expression.from_ = from_ - builder.append(step) - - name = builder.create_name(edge_name) - node_step = NodeQueryStep( - name=name, - expression=dm.query.NodeResultSetExpression( - from_=edge_name, - filter=item._assemble_filter(), - ), - result_cls=item._result_cls, - ) - builder.append(node_step) - elif isinstance(item, EdgeQueryCore): - step = EdgeQueryStep( - name=name, - expression=cast(dm.query.EdgeResultSetExpression, item._expression), - result_cls=item._result_cls, - ) - step.expression.from_ = from_ - step.expression.filter = item._assemble_filter() - builder.append(step) - else: - raise TypeError(f"Unsupported query step type: {type(item._expression)}") - - is_last_reverse_list = item._connection_type == "reverse-list" - first = False - from_ = name - return builder - - -class EdgeQueryCore(QueryCore[T_DomainList, T_DomainListEnd]): - _result_cls: ClassVar[type[DomainRelation]] - - -@dataclass(frozen=True) -class ViewPropertyId(CogniteObject): - view: dm.ViewId - property: str - - @classmethod - def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> "ViewPropertyId": - return cls( - view=dm.ViewId.load(resource["view"]), - property=resource["identifier"], - ) - - def dump(self, camel_case: bool = True) -> dict[str, Any]: - return { - "view": self.view.dump(camel_case=camel_case, include_type=False), - "identifier": self.property, - } - - -class QueryReducingBatchSize(UserWarning): - """Raised when a query is too large and the batch size must be reduced.""" - - ... - - -def chunker(sequence: Sequence, chunk_size: int) -> Iterator[Sequence]: - """ - Split a sequence into chunks of size chunk_size. - - Args: - sequence: The sequence to split. - chunk_size: The size of each chunk. - - Returns: - An iterator over the chunks. - - """ - for i in range(0, len(sequence), chunk_size): - yield sequence[i : i + chunk_size] - - -class QueryStep: - def __init__( - self, - name: str, - expression: dm.query.ResultSetExpression, - view_id: dm.ViewId | None = None, - max_retrieve_limit: int = -1, - select: dm.query.Select | None | type[_NotSetSentinel] = _NotSetSentinel, - raw_filter: dm.Filter | None = None, - connection_type: Literal["reverse-list"] | None = None, - view_property: ViewPropertyId | None = None, - selected_properties: list[str] | None = None, - ): - self.name = name - self.expression = expression - self.view_id = view_id - self.max_retrieve_limit = max_retrieve_limit - self.select: dm.query.Select | None - if select is _NotSetSentinel: - try: - self.select = self._default_select() - except NotImplementedError: - raise ValueError(f"You need to provide a select to instantiate a {type(self).__name__}") from None - else: - self.select = select # type: ignore[assignment] - self.raw_filter = raw_filter - self.connection_type = connection_type - self.view_property = view_property - self.selected_properties = selected_properties - self._max_retrieve_batch_limit = ACTUAL_INSTANCE_QUERY_LIMIT - self.cursor: str | None = None - self.total_retrieved: int = 0 - self.last_batch_count: int = 0 - self.results: list[Instance] = [] - - def _default_select(self) -> dm.query.Select: - if self.view_id is None: - return dm.query.Select() - else: - return dm.query.Select([dm.query.SourceSelector(self.view_id, ["*"])]) - - @property - def is_queryable(self) -> bool: - # We cannot query across reverse-list connections - return self.connection_type != "reverse-list" - - @property - def from_(self) -> str | None: - return self.expression.from_ - - @property - def is_single_direct_relation(self) -> bool: - return isinstance(self.expression, dm.query.NodeResultSetExpression) and self.expression.through is not None - - @property - def node_expression(self) -> dm.query.NodeResultSetExpression | None: - if isinstance(self.expression, dm.query.NodeResultSetExpression): - return self.expression - return None - - @property - def edge_expression(self) -> dm.query.EdgeResultSetExpression | None: - if isinstance(self.expression, dm.query.EdgeResultSetExpression): - return self.expression - return None - - @property - def node_results(self) -> Iterable[dm.Node]: - return (item for item in self.results if isinstance(item, dm.Node)) - - @property - def edge_results(self) -> Iterable[dm.Edge]: - return (item for item in self.results if isinstance(item, dm.Edge)) - - def update_expression_limit(self) -> None: - if self.is_unlimited: - self.expression.limit = self._max_retrieve_batch_limit - else: - self.expression.limit = max(min(INSTANCE_QUERY_LIMIT, self.max_retrieve_limit - self.total_retrieved), 0) - - def reduce_max_batch_limit(self) -> bool: - self._max_retrieve_batch_limit = max(1, self._max_retrieve_batch_limit // 2) - return self._max_retrieve_batch_limit > 1 - - @property - def is_unlimited(self) -> bool: - return self.max_retrieve_limit in {None, -1, math.inf} - - @property - def is_finished(self) -> bool: - return ( - (not self.is_unlimited and self.total_retrieved >= self.max_retrieve_limit) - or self.cursor is None - or self.last_batch_count == 0 - # Single direct relations are dependent on the parent node, - # so we assume that the parent node is the limiting factor. - or self.is_single_direct_relation - ) - - def count_total(self, cognite_client: CogniteClient) -> float: - if self.view_id is None: - raise ValueError("Cannot count total if select is not set") - - return cognite_client.data_modeling.instances.aggregate( - self.view_id, Count("externalId"), filter=self.raw_filter - ).value - - def __repr__(self) -> str: - return f"{self.__class__.__name__}(name={self.name!r}, from={self.from_!r}, results={len(self.results)})" - - -class QueryBuilder(list, MutableSequence[QueryStep]): - """This is a helper class to build and execute a query. It is responsible for - doing the paging of the query and keeping track of the results.""" - - def __init__(self, steps: Collection[QueryStep] | None = None): - super().__init__(steps or []) - - def _reset(self): - for expression in self: - expression.total_retrieved = 0 - expression.cursor = None - expression.results = [] - - def _update_expression_limits(self) -> None: - for expression in self: - expression.update_expression_limit() - - def _build(self) -> tuple[dm.query.Query, list[QueryStep], set[str]]: - with_ = {step.name: step.expression for step in self if step.is_queryable} - select = {step.name: step.select for step in self if step.select is not None and step.is_queryable} - cursors = self._cursors - - step_by_name = {step.name: step for step in self} - search: list[QueryStep] = [] - temporary_select: set[str] = set() - for step in self: - if step.is_queryable: - continue - if step.node_expression is not None: - search.append(step) - # Ensure that select is set for the parent - if step.from_ in select or step.from_ is None: - continue - view_id = step_by_name[step.from_].view_id - if view_id is None: - continue - select[step.from_] = dm.query.Select([dm.query.SourceSelector(view_id, ["*"])]) - temporary_select.add(step.from_) - return dm.query.Query(with_=with_, select=select, cursors=cursors), search, temporary_select - - def _dump_yaml(self) -> str: - return self._build()[0].dump_yaml() - - @property - def _cursors(self) -> dict[str, str | None]: - return {expression.name: expression.cursor for expression in self if expression.is_queryable} - - def _update(self, batch: dm.query.QueryResult): - for expression in self: - if expression.name not in batch: - continue - expression.last_batch_count = len(batch[expression.name]) - expression.total_retrieved += expression.last_batch_count - expression.cursor = batch.cursors.get(expression.name) - expression.results.extend(batch[expression.name].data) - - @property - def _is_finished(self) -> bool: - return self[0].is_finished - - def _reduce_max_batch_limit(self) -> bool: - for expression in self: - if not expression.reduce_max_batch_limit(): - return False - return True - - def execute_query(self, client: CogniteClient, remove_not_connected: bool = False) -> dict[str, list[Instance]]: - self._reset() - query, to_search, temp_select = self._build() - - if not self: - raise ValueError("No query steps to execute") - - count: float | None = None - with suppress(ValueError, CogniteAPIError): - count = self[0].count_total(client) - - is_large_query = False - last_progress_print = 0 - nodes_per_second = 0.0 - while True: - self._update_expression_limits() - query.cursors = self._cursors - t0 = time.time() - try: - batch = client.data_modeling.instances.query(query) - except CogniteAPIError as e: - if e.code == 408: - # Too big query, try to reduce the limit - if self._reduce_max_batch_limit(): - continue - new_limit = self[0]._max_retrieve_batch_limit - warnings.warn( - f"Query is too large, reducing batch size to {new_limit:,}, and trying again", - QueryReducingBatchSize, - stacklevel=2, - ) - - raise e - - self._fetch_reverse_direct_relation_of_lists(client, to_search, batch) - - for name in temp_select: - batch.pop(name, None) - - last_execution_time = time.time() - t0 - - self._update(batch) - if self._is_finished: - break - - if count is None: - continue - # Estimate the number of nodes per second using exponential moving average - last_batch_nodes_per_second = len(batch[self[0].name]) / last_execution_time - if nodes_per_second == 0.0: - nodes_per_second = last_batch_nodes_per_second - else: - nodes_per_second = 0.1 * last_batch_nodes_per_second + 0.9 * nodes_per_second - # Estimate the time to completion - remaining_nodes = count - self[0].total_retrieved - remaining_time = remaining_nodes / nodes_per_second - - if is_large_query and (self[0].total_retrieved - last_progress_print) > PRINT_PROGRESS_PER_N_NODES: - estimate = datetime.timedelta(seconds=round(remaining_time, 0)) - print( - f"Progress: {self[0].total_retrieved:,}/{count:,} nodes retrieved. " - f"Estimated time to completion: {estimate}" - ) - last_progress_print = self[0].total_retrieved - - if is_large_query is False and remaining_time > MINIMUM_ESTIMATED_SECONDS_BEFORE_PRINT_PROGRESS: - is_large_query = True - print("Large query detected. Will print progress.") - - if remove_not_connected and len(self) > 1: - _QueryResultCleaner(self).clean() - - return {step.name: step.results for step in self} - - @staticmethod - def _fetch_reverse_direct_relation_of_lists( - client: CogniteClient, to_search: list[QueryStep], batch: dm.query.QueryResult - ) -> None: - """Reverse direct relations for lists are not supported by the query API. - This method fetches them separately.""" - for step in to_search: - if step.from_ is None or step.from_ not in batch: - continue - item_ids = [node.as_id() for node in batch[step.from_].data] - if not item_ids: - continue - - view_id = step.view_id - expression = step.node_expression - if view_id is None or expression is None: - raise ValueError( - "Invalid state of the query. Search should always be a node expression with view properties" - ) - if expression.through is None: - raise ValueError("Missing through set in a reverse-list query") - limit = SEARCH_LIMIT if step.is_unlimited else min(step.max_retrieve_limit, SEARCH_LIMIT) - - step_result = dm.NodeList[dm.Node]([]) - for item_ids_chunk in chunker(item_ids, IN_FILTER_CHUNK_SIZE): - is_items = dm.filters.In(view_id.as_property_ref(expression.through.property), item_ids_chunk) - is_selected = is_items if step.raw_filter is None else dm.filters.And(is_items, step.raw_filter) - - chunk_result = client.data_modeling.instances.search( - view_id, properties=None, filter=is_selected, limit=limit - ) - step_result.extend(chunk_result) - - batch[step.name] = dm.NodeListWithCursor(step_result, None) - return None - - def get_from(self) -> str | None: - if len(self) == 0: - return None - return self[-1].name - - def create_name(self, from_: str | None) -> str: - if from_ is None: - return "0" - return f"{from_}_{len(self)}" - - def append(self, __object: QueryStep, /) -> None: - # Extra validation to ensure all assumptions are met - if len(self) == 0: - if __object.from_ is not None: - raise ValueError("The first step should not have a 'from_' value") - else: - if __object.from_ is None: - raise ValueError("The 'from_' value should be set") - super().append(__object) - - def extend(self, __iterable: Iterable[QueryStep], /) -> None: - for item in __iterable: - self.append(item) - - # The implementations below are to get proper type hints - def __iter__(self) -> Iterator[QueryStep]: - return super().__iter__() - - @overload - def __getitem__(self, item: SupportsIndex) -> QueryStep: ... - - @overload - def __getitem__(self, item: slice) -> "QueryBuilder": ... - - def __getitem__(self, item: SupportsIndex | slice) -> "QueryStep | QueryBuilder": - value = super().__getitem__(item) - if isinstance(item, slice): - return QueryBuilder(value) # type: ignore[arg-type] - return cast(QueryStep, value) - - -class _QueryResultCleaner: - """Remove nodes and edges that are not connected through the entire query""" - - def __init__(self, steps: list[QueryStep]): - self._tree = self._create_tree(steps) - self._root = steps[0] - - @classmethod - def _create_tree(cls, steps: list[QueryStep]) -> dict[str, list[QueryStep]]: - tree: dict[str, list[QueryStep]] = defaultdict(list) - for step in steps: - if step.from_ is None: - continue - tree[step.from_].append(step) - return dict(tree) - - def clean(self) -> None: - self._clean(self._root) - - @staticmethod - def as_node_id(direct_relation: dm.DirectRelationReference | dict[str, str]) -> dm.NodeId: - if isinstance(direct_relation, dict): - return dm.NodeId(direct_relation["space"], direct_relation["externalId"]) - - return dm.NodeId(direct_relation.space, direct_relation.external_id) - - def _clean(self, step: QueryStep) -> tuple[set[dm.NodeId], str | None]: - if step.name not in self._tree: - # Leaf Node - direct_relation: str | None = None - if step.node_expression and (through := step.node_expression.through) is not None: - direct_relation = through.property - if step.node_expression.direction == "inwards": - return { - node_id for item in step.node_results for node_id in self._get_relations(item, direct_relation) - }, None - - return {item.as_id() for item in step.results}, direct_relation # type: ignore[attr-defined] - - expected_ids_by_property: dict[str | None, set[dm.NodeId]] = {} - for child in self._tree[step.name]: - child_ids, property_id = self._clean(child) - if property_id not in expected_ids_by_property: - expected_ids_by_property[property_id] = child_ids - else: - expected_ids_by_property[property_id] |= child_ids - - if step.node_expression is not None: - filtered_results: list[Instance] = [] - for node in step.node_results: - if self._is_connected_node(node, expected_ids_by_property): - filtered_results.append(node) - step.results = filtered_results - direct_relation = None if step.node_expression.through is None else step.node_expression.through.property - return {node.as_id() for node in step.node_results}, direct_relation - - if step.edge_expression: - if len(expected_ids_by_property) > 1 or None not in expected_ids_by_property: - raise RuntimeError(f"Invalid state of {type(self).__name__}") - expected_ids = expected_ids_by_property[None] - if step.edge_expression.direction == "outwards": - step.results = [edge for edge in step.edge_results if self.as_node_id(edge.end_node) in expected_ids] - return {self.as_node_id(edge.start_node) for edge in step.edge_results}, None - else: # inwards - step.results = [edge for edge in step.edge_results if self.as_node_id(edge.start_node) in expected_ids] - return {self.as_node_id(edge.end_node) for edge in step.edge_results}, None - - raise TypeError(f"Unsupported query step type: {type(step)}") - - @classmethod - def _is_connected_node(cls, node: dm.Node, expected_ids_by_property: dict[str | None, set[dm.NodeId]]) -> bool: - if not expected_ids_by_property: - return True - if None in expected_ids_by_property: - if node.as_id() in expected_ids_by_property[None]: - return True - if len(expected_ids_by_property) == 1: - return False - node_properties = next(iter(node.properties.values())) - for property_id, expected_ids in expected_ids_by_property.items(): - if property_id is None: - continue - value = node_properties.get(property_id) - if value is None: - continue - elif isinstance(value, list): - if {cls.as_node_id(item) for item in value if isinstance(item, dict)} & expected_ids: - return True - elif isinstance(value, dict) and cls.as_node_id(value) in expected_ids: - return True - return False - - @classmethod - def _get_relations(cls, node: dm.Node, property_id: str) -> Iterable[dm.NodeId]: - if property_id is None: - return {node.as_id()} - value = next(iter(node.properties.values())).get(property_id) - if isinstance(value, list): - return [cls.as_node_id(item) for item in value if isinstance(item, dict)] - elif isinstance(value, dict): - return [cls.as_node_id(value)] - return [] - - -class NodeQueryStep(QueryStep): - def __init__( - self, - name: str, - expression: dm.query.NodeResultSetExpression, - result_cls: type[DomainModel], - max_retrieve_limit: int = -1, - select: dm.query.Select | None | type[_NotSetSentinel] = _NotSetSentinel, - raw_filter: dm.Filter | None = None, - connection_type: Literal["reverse-list"] | None = None, - ): - self.result_cls = result_cls - super().__init__(name, expression, result_cls._view_id, max_retrieve_limit, select, raw_filter, connection_type) - - def unpack(self) -> dict[dm.NodeId | str, DomainModel]: - return { - ( - instance.as_id() if instance.space != DEFAULT_INSTANCE_SPACE else instance.external_id - ): self.result_cls.from_instance(instance) - for instance in cast(list[dm.Node], self.results) - } - - @property - def node_results(self) -> list[dm.Node]: - return cast(list[dm.Node], self.results) - - @property - def node_expression(self) -> dm.query.NodeResultSetExpression: - return cast(dm.query.NodeResultSetExpression, self.expression) - - -class EdgeQueryStep(QueryStep): - def __init__( - self, - name: str, - expression: dm.query.EdgeResultSetExpression, - result_cls: type[DomainRelation] | None = None, - max_retrieve_limit: int = -1, - select: dm.query.Select | None | type[_NotSetSentinel] = _NotSetSentinel, - raw_filter: dm.Filter | None = None, - ): - self.result_cls = result_cls - view_id = result_cls._view_id if result_cls is not None else None - super().__init__(name, expression, view_id, max_retrieve_limit, select, raw_filter, None) - - def unpack(self) -> dict[dm.NodeId, list[dm.Edge | DomainRelation]]: - output: dict[dm.NodeId, list[dm.Edge | DomainRelation]] = defaultdict(list) - for edge in cast(list[dm.Edge], self.results): - edge_source = edge.start_node if self.expression.direction == "outwards" else edge.end_node - value = self.result_cls.from_instance(edge) if self.result_cls is not None else edge - output[as_node_id(edge_source)].append(value) # type: ignore[arg-type] - return output - - @property - def edge_results(self) -> list[dm.Edge]: - return cast(list[dm.Edge], self.results) - - @property - def edge_expression(self) -> dm.query.EdgeResultSetExpression: - return cast(dm.query.EdgeResultSetExpression, self.expression) - - -class DataClassQueryBuilder(QueryBuilder, Generic[T_DomainModelList]): - """This is a helper class to build and execute a query. It is responsible for - doing the paging of the query and keeping track of the results.""" - - def __init__( - self, - result_cls: type[T_DomainModelList] | None, - steps: Collection[QueryStep] | None = None, - return_step: Literal["first", "last"] | None = None, - ): - super().__init__(steps or []) - self._result_list_cls = result_cls - self._return_step: Literal["first", "last"] | None = return_step - - def unpack(self) -> T_DomainModelList: - if self._result_list_cls is None: - raise ValueError("No result class set, unable to unpack results") - selected = [step for step in self if step.select is not None] - if len(selected) == 0: - return self._result_list_cls([]) - elif len(selected) == 1: - # Validated in the append method - if self._return_step == "first": - selected_step = cast(NodeQueryStep, self[0]) - elif self._return_step == "last": - selected_step = cast(NodeQueryStep, self[-1]) - else: - raise ValueError(f"Invalid return_step: {self._return_step}") - return self._result_list_cls(selected_step.unpack().values()) - # More than one step, we need to unpack the nodes and edges - nodes_by_from: dict[str | None, dict[dm.NodeId | str, DomainModel]] = defaultdict(dict) - edges_by_from: dict[str, dict[dm.NodeId, list[dm.Edge | DomainRelation]]] = defaultdict(dict) - for step in reversed(self): - # Validated in the append method - from_ = cast(str, step.from_) - if isinstance(step, EdgeQueryStep): - edges_by_from[from_].update(step.unpack()) - if step.name in nodes_by_from: - nodes_by_from[from_].update(nodes_by_from[step.name]) - del nodes_by_from[step.name] - elif isinstance(step, NodeQueryStep): - unpacked = step.unpack() - nodes_by_from[from_].update(unpacked) # type: ignore[arg-type] - if step.name in nodes_by_from or step.name in edges_by_from: - step.result_cls._update_connections( - unpacked, # type: ignore[arg-type] - nodes_by_from.get(step.name, {}), # type: ignore[arg-type] - edges_by_from.get(step.name, {}), - ) - if self._return_step == "first": - return self._result_list_cls(nodes_by_from[None].values()) - elif self._return_step == "last" and self[-1].from_ in nodes_by_from: - return self._result_list_cls(nodes_by_from[self[-1].from_].values()) - elif self._return_step == "last": - raise ValueError("Cannot return the last step when the last step is an edge query") - else: - raise ValueError(f"Invalid return_step: {self._return_step}") - - def append(self, __object: QueryStep, /) -> None: - # Extra validation to ensure all assumptions are met - if len(self) == 0: - if __object.from_ is not None: - raise ValueError("The first step should not have a 'from_' value") - if self._result_list_cls is None: - if self._return_step is None: - self._return_step = "first" - else: - if not isinstance(__object, NodeQueryStep): - raise ValueError("The first step should be a NodeQueryStep") - # If the first step is a NodeQueryStep, and matches the instance - # in the result_list_cls we can return the result from the first step - # Alternative is result_cls is not set, then we also assume that the first step - if self._return_step is None: - if __object.result_cls is self._result_list_cls._INSTANCE: - self._return_step = "first" - else: - # If not, we assume that the last step is the one we want to return - self._return_step = "last" - else: - if __object.from_ is None: - raise ValueError("The 'from_' value should be set") - super().append(__object) - - def extend(self, __iterable: Iterable[QueryStep], /) -> None: - for item in __iterable: - self.append(item) - - # The implementations below are to get proper type hints - def __iter__(self) -> Iterator[QueryStep]: - return super().__iter__() - - @overload - def __getitem__(self, item: SupportsIndex) -> QueryStep: ... - - @overload - def __getitem__(self, item: slice) -> DataClassQueryBuilder[T_DomainModelList]: ... - - def __getitem__(self, item: SupportsIndex | slice) -> QueryStep | DataClassQueryBuilder[T_DomainModelList]: - value = super().__getitem__(item) - if isinstance(item, slice): - return DataClassQueryBuilder(self._result_list_cls, value) # type: ignore[arg-type] - return cast(QueryStep, value) - - -T_QueryCore = TypeVar("T_QueryCore") - - -class Filtering(Generic[T_QueryCore], ABC): - def __init__(self, query: T_QueryCore, prop_path: list[str] | tuple[str, ...]): - self._query = query - self._prop_path = prop_path - self._filter: dm.Filter | None = None - - def _raise_if_filter_set(self): - if self._filter is not None: - raise ValueError("Filter has already been set") - - def _as_filter(self) -> dm.Filter | None: - return self._filter - - -class StringFilter(Filtering[T_QueryCore]): - def equals(self, value: str) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Equals(self._prop_path, value) - return self._query - - def prefix(self, prefix: str) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Prefix(self._prop_path, prefix) - return self._query - - def in_(self, values: list[str]) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.In(self._prop_path, values) - return self._query - - -class BooleanFilter(Filtering[T_QueryCore]): - def equals(self, value: bool) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Equals(self._prop_path, value) - return self._query - - -class IntFilter(Filtering[T_QueryCore]): - def range(self, gte: int | None, lte: int | None) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Range(self._prop_path, gte=gte, lte=lte) - return self._query - - -class FloatFilter(Filtering[T_QueryCore]): - def range(self, gte: float | None, lte: float | None) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Range(self._prop_path, gte=gte, lte=lte) - return self._query - - -class TimestampFilter(Filtering[T_QueryCore]): - def range(self, gte: datetime.datetime | None, lte: datetime.datetime | None) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Range( - self._prop_path, - gte=gte.isoformat(timespec="milliseconds") if gte else None, - lte=lte.isoformat(timespec="milliseconds") if lte else None, - ) - return self._query - - -class DateFilter(Filtering[T_QueryCore]): - def range(self, gte: datetime.date | None, lte: datetime.date | None) -> T_QueryCore: - self._raise_if_filter_set() - self._filter = dm.filters.Range( - self._prop_path, - gte=gte.isoformat() if gte else None, - lte=lte.isoformat() if lte else None, - ) - return self._query diff --git a/examples/windmill/data_classes/_gearbox.py b/examples/windmill/data_classes/_gearbox.py deleted file mode 100644 index 1c00b2925..000000000 --- a/examples/windmill/data_classes/_gearbox.py +++ /dev/null @@ -1,370 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - - -__all__ = [ - "Gearbox", - "GearboxWrite", - "GearboxApply", - "GearboxList", - "GearboxWriteList", - "GearboxApplyList", - "GearboxFields", - "GearboxTextFields", - "GearboxGraphQL", -] - - -GearboxTextFields = Literal["external_id", "displacement_x", "displacement_y", "displacement_z"] -GearboxFields = Literal["external_id", "displacement_x", "displacement_y", "displacement_z"] - -_GEARBOX_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "displacement_x": "displacement_x", - "displacement_y": "displacement_y", - "displacement_z": "displacement_z", -} - - -class GearboxGraphQL(GraphQLCore): - """This represents the reading version of gearbox, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the gearbox. - data_record: The data record of the gearbox node. - displacement_x: The displacement x field. - displacement_y: The displacement y field. - displacement_z: The displacement z field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Gearbox", "1") - displacement_x: Optional[TimeSeriesGraphQL] = None - displacement_y: Optional[TimeSeriesGraphQL] = None - displacement_z: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> Gearbox: - """Convert this GraphQL format of gearbox to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return Gearbox( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - displacement_x=self.displacement_x.as_read() if self.displacement_x else None, - displacement_y=self.displacement_y.as_read() if self.displacement_y else None, - displacement_z=self.displacement_z.as_read() if self.displacement_z else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> GearboxWrite: - """Convert this GraphQL format of gearbox to the writing format.""" - return GearboxWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - displacement_x=self.displacement_x.as_write() if self.displacement_x else None, - displacement_y=self.displacement_y.as_write() if self.displacement_y else None, - displacement_z=self.displacement_z.as_write() if self.displacement_z else None, - ) - - -class Gearbox(DomainModel): - """This represents the reading version of gearbox. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the gearbox. - data_record: The data record of the gearbox node. - displacement_x: The displacement x field. - displacement_y: The displacement y field. - displacement_z: The displacement z field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Gearbox", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - displacement_x: Union[TimeSeries, str, None] = None - displacement_y: Union[TimeSeries, str, None] = None - displacement_z: Union[TimeSeries, str, None] = None - - def as_write(self) -> GearboxWrite: - """Convert this read version of gearbox to the writing version.""" - return GearboxWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - displacement_x=( - self.displacement_x.as_write() - if isinstance(self.displacement_x, CogniteTimeSeries) - else self.displacement_x - ), - displacement_y=( - self.displacement_y.as_write() - if isinstance(self.displacement_y, CogniteTimeSeries) - else self.displacement_y - ), - displacement_z=( - self.displacement_z.as_write() - if isinstance(self.displacement_z, CogniteTimeSeries) - else self.displacement_z - ), - ) - - def as_apply(self) -> GearboxWrite: - """Convert this read version of gearbox to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class GearboxWrite(DomainModelWrite): - """This represents the writing version of gearbox. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the gearbox. - data_record: The data record of the gearbox node. - displacement_x: The displacement x field. - displacement_y: The displacement y field. - displacement_z: The displacement z field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Gearbox", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - displacement_x: Union[TimeSeriesWrite, str, None] = None - displacement_y: Union[TimeSeriesWrite, str, None] = None - displacement_z: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.displacement_x is not None or write_none: - properties["displacement_x"] = ( - self.displacement_x - if isinstance(self.displacement_x, str) or self.displacement_x is None - else self.displacement_x.external_id - ) - - if self.displacement_y is not None or write_none: - properties["displacement_y"] = ( - self.displacement_y - if isinstance(self.displacement_y, str) or self.displacement_y is None - else self.displacement_y.external_id - ) - - if self.displacement_z is not None or write_none: - properties["displacement_z"] = ( - self.displacement_z - if isinstance(self.displacement_z, str) or self.displacement_z is None - else self.displacement_z.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.displacement_x, CogniteTimeSeriesWrite): - resources.time_series.append(self.displacement_x) - - if isinstance(self.displacement_y, CogniteTimeSeriesWrite): - resources.time_series.append(self.displacement_y) - - if isinstance(self.displacement_z, CogniteTimeSeriesWrite): - resources.time_series.append(self.displacement_z) - - return resources - - -class GearboxApply(GearboxWrite): - def __new__(cls, *args, **kwargs) -> GearboxApply: - warnings.warn( - "GearboxApply is deprecated and will be removed in v1.0. Use GearboxWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "Gearbox.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class GearboxList(DomainModelList[Gearbox]): - """List of gearboxes in the read version.""" - - _INSTANCE = Gearbox - - def as_write(self) -> GearboxWriteList: - """Convert these read versions of gearbox to the writing versions.""" - return GearboxWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> GearboxWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class GearboxWriteList(DomainModelWriteList[GearboxWrite]): - """List of gearboxes in the writing version.""" - - _INSTANCE = GearboxWrite - - -class GearboxApplyList(GearboxWriteList): ... - - -def _create_gearbox_filter( - view_id: dm.ViewId, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _GearboxQuery(NodeQueryCore[T_DomainModelList, GearboxList]): - _view_id = Gearbox._view_id - _result_cls = Gearbox - _result_list_cls_end = GearboxList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_gearbox(self, limit: int = DEFAULT_QUERY_LIMIT) -> GearboxList: - return self._list(limit=limit) - - -class GearboxQuery(_GearboxQuery[GearboxList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, GearboxList) diff --git a/examples/windmill/data_classes/_generator.py b/examples/windmill/data_classes/_generator.py deleted file mode 100644 index 70e7351b1..000000000 --- a/examples/windmill/data_classes/_generator.py +++ /dev/null @@ -1,359 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - - -__all__ = [ - "Generator", - "GeneratorWrite", - "GeneratorApply", - "GeneratorList", - "GeneratorWriteList", - "GeneratorApplyList", - "GeneratorFields", - "GeneratorTextFields", - "GeneratorGraphQL", -] - - -GeneratorTextFields = Literal["external_id", "generator_speed_controller", "generator_speed_controller_reference"] -GeneratorFields = Literal["external_id", "generator_speed_controller", "generator_speed_controller_reference"] - -_GENERATOR_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "generator_speed_controller": "generator_speed_controller", - "generator_speed_controller_reference": "generator_speed_controller_reference", -} - - -class GeneratorGraphQL(GraphQLCore): - """This represents the reading version of generator, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the generator. - data_record: The data record of the generator node. - generator_speed_controller: The generator speed controller field. - generator_speed_controller_reference: The generator speed controller reference field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Generator", "1") - generator_speed_controller: Optional[TimeSeriesGraphQL] = None - generator_speed_controller_reference: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> Generator: - """Convert this GraphQL format of generator to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return Generator( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - generator_speed_controller=( - self.generator_speed_controller.as_read() if self.generator_speed_controller else None - ), - generator_speed_controller_reference=( - self.generator_speed_controller_reference.as_read() - if self.generator_speed_controller_reference - else None - ), - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> GeneratorWrite: - """Convert this GraphQL format of generator to the writing format.""" - return GeneratorWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - generator_speed_controller=( - self.generator_speed_controller.as_write() if self.generator_speed_controller else None - ), - generator_speed_controller_reference=( - self.generator_speed_controller_reference.as_write() - if self.generator_speed_controller_reference - else None - ), - ) - - -class Generator(DomainModel): - """This represents the reading version of generator. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the generator. - data_record: The data record of the generator node. - generator_speed_controller: The generator speed controller field. - generator_speed_controller_reference: The generator speed controller reference field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Generator", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - generator_speed_controller: Union[TimeSeries, str, None] = None - generator_speed_controller_reference: Union[TimeSeries, str, None] = None - - def as_write(self) -> GeneratorWrite: - """Convert this read version of generator to the writing version.""" - return GeneratorWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - generator_speed_controller=( - self.generator_speed_controller.as_write() - if isinstance(self.generator_speed_controller, CogniteTimeSeries) - else self.generator_speed_controller - ), - generator_speed_controller_reference=( - self.generator_speed_controller_reference.as_write() - if isinstance(self.generator_speed_controller_reference, CogniteTimeSeries) - else self.generator_speed_controller_reference - ), - ) - - def as_apply(self) -> GeneratorWrite: - """Convert this read version of generator to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class GeneratorWrite(DomainModelWrite): - """This represents the writing version of generator. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the generator. - data_record: The data record of the generator node. - generator_speed_controller: The generator speed controller field. - generator_speed_controller_reference: The generator speed controller reference field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Generator", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - generator_speed_controller: Union[TimeSeriesWrite, str, None] = None - generator_speed_controller_reference: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.generator_speed_controller is not None or write_none: - properties["generator_speed_controller"] = ( - self.generator_speed_controller - if isinstance(self.generator_speed_controller, str) or self.generator_speed_controller is None - else self.generator_speed_controller.external_id - ) - - if self.generator_speed_controller_reference is not None or write_none: - properties["generator_speed_controller_reference"] = ( - self.generator_speed_controller_reference - if isinstance(self.generator_speed_controller_reference, str) - or self.generator_speed_controller_reference is None - else self.generator_speed_controller_reference.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.generator_speed_controller, CogniteTimeSeriesWrite): - resources.time_series.append(self.generator_speed_controller) - - if isinstance(self.generator_speed_controller_reference, CogniteTimeSeriesWrite): - resources.time_series.append(self.generator_speed_controller_reference) - - return resources - - -class GeneratorApply(GeneratorWrite): - def __new__(cls, *args, **kwargs) -> GeneratorApply: - warnings.warn( - "GeneratorApply is deprecated and will be removed in v1.0. Use GeneratorWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "Generator.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class GeneratorList(DomainModelList[Generator]): - """List of generators in the read version.""" - - _INSTANCE = Generator - - def as_write(self) -> GeneratorWriteList: - """Convert these read versions of generator to the writing versions.""" - return GeneratorWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> GeneratorWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class GeneratorWriteList(DomainModelWriteList[GeneratorWrite]): - """List of generators in the writing version.""" - - _INSTANCE = GeneratorWrite - - -class GeneratorApplyList(GeneratorWriteList): ... - - -def _create_generator_filter( - view_id: dm.ViewId, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _GeneratorQuery(NodeQueryCore[T_DomainModelList, GeneratorList]): - _view_id = Generator._view_id - _result_cls = Generator - _result_list_cls_end = GeneratorList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_generator(self, limit: int = DEFAULT_QUERY_LIMIT) -> GeneratorList: - return self._list(limit=limit) - - -class GeneratorQuery(_GeneratorQuery[GeneratorList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, GeneratorList) diff --git a/examples/windmill/data_classes/_high_speed_shaft.py b/examples/windmill/data_classes/_high_speed_shaft.py deleted file mode 100644 index 3842c1809..000000000 --- a/examples/windmill/data_classes/_high_speed_shaft.py +++ /dev/null @@ -1,364 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - - -__all__ = [ - "HighSpeedShaft", - "HighSpeedShaftWrite", - "HighSpeedShaftApply", - "HighSpeedShaftList", - "HighSpeedShaftWriteList", - "HighSpeedShaftApplyList", - "HighSpeedShaftFields", - "HighSpeedShaftTextFields", - "HighSpeedShaftGraphQL", -] - - -HighSpeedShaftTextFields = Literal["external_id", "bending_moment_y", "bending_monent_x", "torque"] -HighSpeedShaftFields = Literal["external_id", "bending_moment_y", "bending_monent_x", "torque"] - -_HIGHSPEEDSHAFT_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "bending_moment_y": "bending_moment_y", - "bending_monent_x": "bending_monent_x", - "torque": "torque", -} - - -class HighSpeedShaftGraphQL(GraphQLCore): - """This represents the reading version of high speed shaft, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the high speed shaft. - data_record: The data record of the high speed shaft node. - bending_moment_y: The bending moment y field. - bending_monent_x: The bending monent x field. - torque: The torque field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "HighSpeedShaft", "1") - bending_moment_y: Optional[TimeSeriesGraphQL] = None - bending_monent_x: Optional[TimeSeriesGraphQL] = None - torque: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> HighSpeedShaft: - """Convert this GraphQL format of high speed shaft to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return HighSpeedShaft( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - bending_moment_y=self.bending_moment_y.as_read() if self.bending_moment_y else None, - bending_monent_x=self.bending_monent_x.as_read() if self.bending_monent_x else None, - torque=self.torque.as_read() if self.torque else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> HighSpeedShaftWrite: - """Convert this GraphQL format of high speed shaft to the writing format.""" - return HighSpeedShaftWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - bending_moment_y=self.bending_moment_y.as_write() if self.bending_moment_y else None, - bending_monent_x=self.bending_monent_x.as_write() if self.bending_monent_x else None, - torque=self.torque.as_write() if self.torque else None, - ) - - -class HighSpeedShaft(DomainModel): - """This represents the reading version of high speed shaft. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the high speed shaft. - data_record: The data record of the high speed shaft node. - bending_moment_y: The bending moment y field. - bending_monent_x: The bending monent x field. - torque: The torque field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "HighSpeedShaft", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - bending_moment_y: Union[TimeSeries, str, None] = None - bending_monent_x: Union[TimeSeries, str, None] = None - torque: Union[TimeSeries, str, None] = None - - def as_write(self) -> HighSpeedShaftWrite: - """Convert this read version of high speed shaft to the writing version.""" - return HighSpeedShaftWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - bending_moment_y=( - self.bending_moment_y.as_write() - if isinstance(self.bending_moment_y, CogniteTimeSeries) - else self.bending_moment_y - ), - bending_monent_x=( - self.bending_monent_x.as_write() - if isinstance(self.bending_monent_x, CogniteTimeSeries) - else self.bending_monent_x - ), - torque=self.torque.as_write() if isinstance(self.torque, CogniteTimeSeries) else self.torque, - ) - - def as_apply(self) -> HighSpeedShaftWrite: - """Convert this read version of high speed shaft to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class HighSpeedShaftWrite(DomainModelWrite): - """This represents the writing version of high speed shaft. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the high speed shaft. - data_record: The data record of the high speed shaft node. - bending_moment_y: The bending moment y field. - bending_monent_x: The bending monent x field. - torque: The torque field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "HighSpeedShaft", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - bending_moment_y: Union[TimeSeriesWrite, str, None] = None - bending_monent_x: Union[TimeSeriesWrite, str, None] = None - torque: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.bending_moment_y is not None or write_none: - properties["bending_moment_y"] = ( - self.bending_moment_y - if isinstance(self.bending_moment_y, str) or self.bending_moment_y is None - else self.bending_moment_y.external_id - ) - - if self.bending_monent_x is not None or write_none: - properties["bending_monent_x"] = ( - self.bending_monent_x - if isinstance(self.bending_monent_x, str) or self.bending_monent_x is None - else self.bending_monent_x.external_id - ) - - if self.torque is not None or write_none: - properties["torque"] = ( - self.torque if isinstance(self.torque, str) or self.torque is None else self.torque.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.bending_moment_y, CogniteTimeSeriesWrite): - resources.time_series.append(self.bending_moment_y) - - if isinstance(self.bending_monent_x, CogniteTimeSeriesWrite): - resources.time_series.append(self.bending_monent_x) - - if isinstance(self.torque, CogniteTimeSeriesWrite): - resources.time_series.append(self.torque) - - return resources - - -class HighSpeedShaftApply(HighSpeedShaftWrite): - def __new__(cls, *args, **kwargs) -> HighSpeedShaftApply: - warnings.warn( - "HighSpeedShaftApply is deprecated and will be removed in v1.0. Use HighSpeedShaftWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "HighSpeedShaft.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class HighSpeedShaftList(DomainModelList[HighSpeedShaft]): - """List of high speed shafts in the read version.""" - - _INSTANCE = HighSpeedShaft - - def as_write(self) -> HighSpeedShaftWriteList: - """Convert these read versions of high speed shaft to the writing versions.""" - return HighSpeedShaftWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> HighSpeedShaftWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class HighSpeedShaftWriteList(DomainModelWriteList[HighSpeedShaftWrite]): - """List of high speed shafts in the writing version.""" - - _INSTANCE = HighSpeedShaftWrite - - -class HighSpeedShaftApplyList(HighSpeedShaftWriteList): ... - - -def _create_high_speed_shaft_filter( - view_id: dm.ViewId, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _HighSpeedShaftQuery(NodeQueryCore[T_DomainModelList, HighSpeedShaftList]): - _view_id = HighSpeedShaft._view_id - _result_cls = HighSpeedShaft - _result_list_cls_end = HighSpeedShaftList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_high_speed_shaft(self, limit: int = DEFAULT_QUERY_LIMIT) -> HighSpeedShaftList: - return self._list(limit=limit) - - -class HighSpeedShaftQuery(_HighSpeedShaftQuery[HighSpeedShaftList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, HighSpeedShaftList) diff --git a/examples/windmill/data_classes/_main_shaft.py b/examples/windmill/data_classes/_main_shaft.py deleted file mode 100644 index 6dd757f8f..000000000 --- a/examples/windmill/data_classes/_main_shaft.py +++ /dev/null @@ -1,408 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - - -__all__ = [ - "MainShaft", - "MainShaftWrite", - "MainShaftApply", - "MainShaftList", - "MainShaftWriteList", - "MainShaftApplyList", - "MainShaftFields", - "MainShaftTextFields", - "MainShaftGraphQL", -] - - -MainShaftTextFields = Literal[ - "external_id", "bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque" -] -MainShaftFields = Literal[ - "external_id", "bending_x", "bending_y", "calculated_tilt_moment", "calculated_yaw_moment", "torque" -] - -_MAINSHAFT_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "bending_x": "bending_x", - "bending_y": "bending_y", - "calculated_tilt_moment": "calculated_tilt_moment", - "calculated_yaw_moment": "calculated_yaw_moment", - "torque": "torque", -} - - -class MainShaftGraphQL(GraphQLCore): - """This represents the reading version of main shaft, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the main shaft. - data_record: The data record of the main shaft node. - bending_x: The bending x field. - bending_y: The bending y field. - calculated_tilt_moment: The calculated tilt moment field. - calculated_yaw_moment: The calculated yaw moment field. - torque: The torque field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "MainShaft", "1") - bending_x: Optional[TimeSeriesGraphQL] = None - bending_y: Optional[TimeSeriesGraphQL] = None - calculated_tilt_moment: Optional[TimeSeriesGraphQL] = None - calculated_yaw_moment: Optional[TimeSeriesGraphQL] = None - torque: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> MainShaft: - """Convert this GraphQL format of main shaft to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return MainShaft( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - bending_x=self.bending_x.as_read() if self.bending_x else None, - bending_y=self.bending_y.as_read() if self.bending_y else None, - calculated_tilt_moment=self.calculated_tilt_moment.as_read() if self.calculated_tilt_moment else None, - calculated_yaw_moment=self.calculated_yaw_moment.as_read() if self.calculated_yaw_moment else None, - torque=self.torque.as_read() if self.torque else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> MainShaftWrite: - """Convert this GraphQL format of main shaft to the writing format.""" - return MainShaftWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - bending_x=self.bending_x.as_write() if self.bending_x else None, - bending_y=self.bending_y.as_write() if self.bending_y else None, - calculated_tilt_moment=self.calculated_tilt_moment.as_write() if self.calculated_tilt_moment else None, - calculated_yaw_moment=self.calculated_yaw_moment.as_write() if self.calculated_yaw_moment else None, - torque=self.torque.as_write() if self.torque else None, - ) - - -class MainShaft(DomainModel): - """This represents the reading version of main shaft. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the main shaft. - data_record: The data record of the main shaft node. - bending_x: The bending x field. - bending_y: The bending y field. - calculated_tilt_moment: The calculated tilt moment field. - calculated_yaw_moment: The calculated yaw moment field. - torque: The torque field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "MainShaft", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - bending_x: Union[TimeSeries, str, None] = None - bending_y: Union[TimeSeries, str, None] = None - calculated_tilt_moment: Union[TimeSeries, str, None] = None - calculated_yaw_moment: Union[TimeSeries, str, None] = None - torque: Union[TimeSeries, str, None] = None - - def as_write(self) -> MainShaftWrite: - """Convert this read version of main shaft to the writing version.""" - return MainShaftWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - bending_x=self.bending_x.as_write() if isinstance(self.bending_x, CogniteTimeSeries) else self.bending_x, - bending_y=self.bending_y.as_write() if isinstance(self.bending_y, CogniteTimeSeries) else self.bending_y, - calculated_tilt_moment=( - self.calculated_tilt_moment.as_write() - if isinstance(self.calculated_tilt_moment, CogniteTimeSeries) - else self.calculated_tilt_moment - ), - calculated_yaw_moment=( - self.calculated_yaw_moment.as_write() - if isinstance(self.calculated_yaw_moment, CogniteTimeSeries) - else self.calculated_yaw_moment - ), - torque=self.torque.as_write() if isinstance(self.torque, CogniteTimeSeries) else self.torque, - ) - - def as_apply(self) -> MainShaftWrite: - """Convert this read version of main shaft to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class MainShaftWrite(DomainModelWrite): - """This represents the writing version of main shaft. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the main shaft. - data_record: The data record of the main shaft node. - bending_x: The bending x field. - bending_y: The bending y field. - calculated_tilt_moment: The calculated tilt moment field. - calculated_yaw_moment: The calculated yaw moment field. - torque: The torque field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "MainShaft", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - bending_x: Union[TimeSeriesWrite, str, None] = None - bending_y: Union[TimeSeriesWrite, str, None] = None - calculated_tilt_moment: Union[TimeSeriesWrite, str, None] = None - calculated_yaw_moment: Union[TimeSeriesWrite, str, None] = None - torque: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.bending_x is not None or write_none: - properties["bending_x"] = ( - self.bending_x - if isinstance(self.bending_x, str) or self.bending_x is None - else self.bending_x.external_id - ) - - if self.bending_y is not None or write_none: - properties["bending_y"] = ( - self.bending_y - if isinstance(self.bending_y, str) or self.bending_y is None - else self.bending_y.external_id - ) - - if self.calculated_tilt_moment is not None or write_none: - properties["calculated_tilt_moment"] = ( - self.calculated_tilt_moment - if isinstance(self.calculated_tilt_moment, str) or self.calculated_tilt_moment is None - else self.calculated_tilt_moment.external_id - ) - - if self.calculated_yaw_moment is not None or write_none: - properties["calculated_yaw_moment"] = ( - self.calculated_yaw_moment - if isinstance(self.calculated_yaw_moment, str) or self.calculated_yaw_moment is None - else self.calculated_yaw_moment.external_id - ) - - if self.torque is not None or write_none: - properties["torque"] = ( - self.torque if isinstance(self.torque, str) or self.torque is None else self.torque.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.bending_x, CogniteTimeSeriesWrite): - resources.time_series.append(self.bending_x) - - if isinstance(self.bending_y, CogniteTimeSeriesWrite): - resources.time_series.append(self.bending_y) - - if isinstance(self.calculated_tilt_moment, CogniteTimeSeriesWrite): - resources.time_series.append(self.calculated_tilt_moment) - - if isinstance(self.calculated_yaw_moment, CogniteTimeSeriesWrite): - resources.time_series.append(self.calculated_yaw_moment) - - if isinstance(self.torque, CogniteTimeSeriesWrite): - resources.time_series.append(self.torque) - - return resources - - -class MainShaftApply(MainShaftWrite): - def __new__(cls, *args, **kwargs) -> MainShaftApply: - warnings.warn( - "MainShaftApply is deprecated and will be removed in v1.0. Use MainShaftWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "MainShaft.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class MainShaftList(DomainModelList[MainShaft]): - """List of main shafts in the read version.""" - - _INSTANCE = MainShaft - - def as_write(self) -> MainShaftWriteList: - """Convert these read versions of main shaft to the writing versions.""" - return MainShaftWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> MainShaftWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class MainShaftWriteList(DomainModelWriteList[MainShaftWrite]): - """List of main shafts in the writing version.""" - - _INSTANCE = MainShaftWrite - - -class MainShaftApplyList(MainShaftWriteList): ... - - -def _create_main_shaft_filter( - view_id: dm.ViewId, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _MainShaftQuery(NodeQueryCore[T_DomainModelList, MainShaftList]): - _view_id = MainShaft._view_id - _result_cls = MainShaft - _result_list_cls_end = MainShaftList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_main_shaft(self, limit: int = DEFAULT_QUERY_LIMIT) -> MainShaftList: - return self._list(limit=limit) - - -class MainShaftQuery(_MainShaftQuery[MainShaftList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, MainShaftList) diff --git a/examples/windmill/data_classes/_metmast.py b/examples/windmill/data_classes/_metmast.py deleted file mode 100644 index 5d99d972d..000000000 --- a/examples/windmill/data_classes/_metmast.py +++ /dev/null @@ -1,390 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, - FloatFilter, -) - - -__all__ = [ - "Metmast", - "MetmastWrite", - "MetmastApply", - "MetmastList", - "MetmastWriteList", - "MetmastApplyList", - "MetmastFields", - "MetmastTextFields", - "MetmastGraphQL", -] - - -MetmastTextFields = Literal["external_id", "temperature", "tilt_angle", "wind_speed"] -MetmastFields = Literal["external_id", "position", "temperature", "tilt_angle", "wind_speed"] - -_METMAST_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "position": "position", - "temperature": "temperature", - "tilt_angle": "tilt_angle", - "wind_speed": "wind_speed", -} - - -class MetmastGraphQL(GraphQLCore): - """This represents the reading version of metmast, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the metmast. - data_record: The data record of the metmast node. - position: The position field. - temperature: The temperature field. - tilt_angle: The tilt angle field. - wind_speed: The wind speed field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Metmast", "1") - position: Optional[float] = None - temperature: Optional[TimeSeriesGraphQL] = None - tilt_angle: Optional[TimeSeriesGraphQL] = None - wind_speed: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> Metmast: - """Convert this GraphQL format of metmast to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return Metmast( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - position=self.position, - temperature=self.temperature.as_read() if self.temperature else None, - tilt_angle=self.tilt_angle.as_read() if self.tilt_angle else None, - wind_speed=self.wind_speed.as_read() if self.wind_speed else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> MetmastWrite: - """Convert this GraphQL format of metmast to the writing format.""" - return MetmastWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - position=self.position, - temperature=self.temperature.as_write() if self.temperature else None, - tilt_angle=self.tilt_angle.as_write() if self.tilt_angle else None, - wind_speed=self.wind_speed.as_write() if self.wind_speed else None, - ) - - -class Metmast(DomainModel): - """This represents the reading version of metmast. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the metmast. - data_record: The data record of the metmast node. - position: The position field. - temperature: The temperature field. - tilt_angle: The tilt angle field. - wind_speed: The wind speed field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Metmast", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - position: Optional[float] = None - temperature: Union[TimeSeries, str, None] = None - tilt_angle: Union[TimeSeries, str, None] = None - wind_speed: Union[TimeSeries, str, None] = None - - def as_write(self) -> MetmastWrite: - """Convert this read version of metmast to the writing version.""" - return MetmastWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - position=self.position, - temperature=( - self.temperature.as_write() if isinstance(self.temperature, CogniteTimeSeries) else self.temperature - ), - tilt_angle=( - self.tilt_angle.as_write() if isinstance(self.tilt_angle, CogniteTimeSeries) else self.tilt_angle - ), - wind_speed=( - self.wind_speed.as_write() if isinstance(self.wind_speed, CogniteTimeSeries) else self.wind_speed - ), - ) - - def as_apply(self) -> MetmastWrite: - """Convert this read version of metmast to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class MetmastWrite(DomainModelWrite): - """This represents the writing version of metmast. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the metmast. - data_record: The data record of the metmast node. - position: The position field. - temperature: The temperature field. - tilt_angle: The tilt angle field. - wind_speed: The wind speed field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Metmast", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - position: Optional[float] = None - temperature: Union[TimeSeriesWrite, str, None] = None - tilt_angle: Union[TimeSeriesWrite, str, None] = None - wind_speed: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.position is not None or write_none: - properties["position"] = self.position - - if self.temperature is not None or write_none: - properties["temperature"] = ( - self.temperature - if isinstance(self.temperature, str) or self.temperature is None - else self.temperature.external_id - ) - - if self.tilt_angle is not None or write_none: - properties["tilt_angle"] = ( - self.tilt_angle - if isinstance(self.tilt_angle, str) or self.tilt_angle is None - else self.tilt_angle.external_id - ) - - if self.wind_speed is not None or write_none: - properties["wind_speed"] = ( - self.wind_speed - if isinstance(self.wind_speed, str) or self.wind_speed is None - else self.wind_speed.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.temperature, CogniteTimeSeriesWrite): - resources.time_series.append(self.temperature) - - if isinstance(self.tilt_angle, CogniteTimeSeriesWrite): - resources.time_series.append(self.tilt_angle) - - if isinstance(self.wind_speed, CogniteTimeSeriesWrite): - resources.time_series.append(self.wind_speed) - - return resources - - -class MetmastApply(MetmastWrite): - def __new__(cls, *args, **kwargs) -> MetmastApply: - warnings.warn( - "MetmastApply is deprecated and will be removed in v1.0. Use MetmastWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "Metmast.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class MetmastList(DomainModelList[Metmast]): - """List of metmasts in the read version.""" - - _INSTANCE = Metmast - - def as_write(self) -> MetmastWriteList: - """Convert these read versions of metmast to the writing versions.""" - return MetmastWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> MetmastWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class MetmastWriteList(DomainModelWriteList[MetmastWrite]): - """List of metmasts in the writing version.""" - - _INSTANCE = MetmastWrite - - -class MetmastApplyList(MetmastWriteList): ... - - -def _create_metmast_filter( - view_id: dm.ViewId, - min_position: float | None = None, - max_position: float | None = None, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if min_position is not None or max_position is not None: - filters.append(dm.filters.Range(view_id.as_property_ref("position"), gte=min_position, lte=max_position)) - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _MetmastQuery(NodeQueryCore[T_DomainModelList, MetmastList]): - _view_id = Metmast._view_id - _result_cls = Metmast - _result_list_cls_end = MetmastList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - self.position = FloatFilter(self, self._view_id.as_property_ref("position")) - self._filter_classes.extend( - [ - self.space, - self.external_id, - self.position, - ] - ) - - def list_metmast(self, limit: int = DEFAULT_QUERY_LIMIT) -> MetmastList: - return self._list(limit=limit) - - -class MetmastQuery(_MetmastQuery[MetmastList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, MetmastList) diff --git a/examples/windmill/data_classes/_nacelle.py b/examples/windmill/data_classes/_nacelle.py deleted file mode 100644 index 79cbbae44..000000000 --- a/examples/windmill/data_classes/_nacelle.py +++ /dev/null @@ -1,870 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import TYPE_CHECKING, Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import Field -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - -if TYPE_CHECKING: - from windmill.data_classes._gearbox import Gearbox, GearboxList, GearboxGraphQL, GearboxWrite, GearboxWriteList - from windmill.data_classes._generator import ( - Generator, - GeneratorList, - GeneratorGraphQL, - GeneratorWrite, - GeneratorWriteList, - ) - from windmill.data_classes._high_speed_shaft import ( - HighSpeedShaft, - HighSpeedShaftList, - HighSpeedShaftGraphQL, - HighSpeedShaftWrite, - HighSpeedShaftWriteList, - ) - from windmill.data_classes._main_shaft import ( - MainShaft, - MainShaftList, - MainShaftGraphQL, - MainShaftWrite, - MainShaftWriteList, - ) - from windmill.data_classes._power_inverter import ( - PowerInverter, - PowerInverterList, - PowerInverterGraphQL, - PowerInverterWrite, - PowerInverterWriteList, - ) - - -__all__ = [ - "Nacelle", - "NacelleWrite", - "NacelleApply", - "NacelleList", - "NacelleWriteList", - "NacelleApplyList", - "NacelleFields", - "NacelleTextFields", - "NacelleGraphQL", -] - - -NacelleTextFields = Literal[ - "external_id", "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error" -] -NacelleFields = Literal[ - "external_id", "acc_from_back_side_x", "acc_from_back_side_y", "acc_from_back_side_z", "yaw_direction", "yaw_error" -] - -_NACELLE_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "acc_from_back_side_x": "acc_from_back_side_x", - "acc_from_back_side_y": "acc_from_back_side_y", - "acc_from_back_side_z": "acc_from_back_side_z", - "yaw_direction": "yaw_direction", - "yaw_error": "yaw_error", -} - - -class NacelleGraphQL(GraphQLCore): - """This represents the reading version of nacelle, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the nacelle. - data_record: The data record of the nacelle node. - acc_from_back_side_x: The acc from back side x field. - acc_from_back_side_y: The acc from back side y field. - acc_from_back_side_z: The acc from back side z field. - gearbox: The gearbox field. - generator: The generator field. - high_speed_shaft: The high speed shaft field. - main_shaft: The main shaft field. - power_inverter: The power inverter field. - yaw_direction: The yaw direction field. - yaw_error: The yaw error field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Nacelle", "1") - acc_from_back_side_x: Optional[TimeSeriesGraphQL] = None - acc_from_back_side_y: Optional[TimeSeriesGraphQL] = None - acc_from_back_side_z: Optional[TimeSeriesGraphQL] = None - gearbox: Optional[GearboxGraphQL] = Field(default=None, repr=False) - generator: Optional[GeneratorGraphQL] = Field(default=None, repr=False) - high_speed_shaft: Optional[HighSpeedShaftGraphQL] = Field(default=None, repr=False) - main_shaft: Optional[MainShaftGraphQL] = Field(default=None, repr=False) - power_inverter: Optional[PowerInverterGraphQL] = Field(default=None, repr=False) - yaw_direction: Optional[TimeSeriesGraphQL] = None - yaw_error: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - @field_validator("gearbox", "generator", "high_speed_shaft", "main_shaft", "power_inverter", mode="before") - def parse_graphql(cls, value: Any) -> Any: - if not isinstance(value, dict): - return value - if "items" in value: - return value["items"] - return value - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> Nacelle: - """Convert this GraphQL format of nacelle to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return Nacelle( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - acc_from_back_side_x=self.acc_from_back_side_x.as_read() if self.acc_from_back_side_x else None, - acc_from_back_side_y=self.acc_from_back_side_y.as_read() if self.acc_from_back_side_y else None, - acc_from_back_side_z=self.acc_from_back_side_z.as_read() if self.acc_from_back_side_z else None, - gearbox=self.gearbox.as_read() if isinstance(self.gearbox, GraphQLCore) else self.gearbox, - generator=self.generator.as_read() if isinstance(self.generator, GraphQLCore) else self.generator, - high_speed_shaft=( - self.high_speed_shaft.as_read() - if isinstance(self.high_speed_shaft, GraphQLCore) - else self.high_speed_shaft - ), - main_shaft=self.main_shaft.as_read() if isinstance(self.main_shaft, GraphQLCore) else self.main_shaft, - power_inverter=( - self.power_inverter.as_read() if isinstance(self.power_inverter, GraphQLCore) else self.power_inverter - ), - yaw_direction=self.yaw_direction.as_read() if self.yaw_direction else None, - yaw_error=self.yaw_error.as_read() if self.yaw_error else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> NacelleWrite: - """Convert this GraphQL format of nacelle to the writing format.""" - return NacelleWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - acc_from_back_side_x=self.acc_from_back_side_x.as_write() if self.acc_from_back_side_x else None, - acc_from_back_side_y=self.acc_from_back_side_y.as_write() if self.acc_from_back_side_y else None, - acc_from_back_side_z=self.acc_from_back_side_z.as_write() if self.acc_from_back_side_z else None, - gearbox=self.gearbox.as_write() if isinstance(self.gearbox, GraphQLCore) else self.gearbox, - generator=self.generator.as_write() if isinstance(self.generator, GraphQLCore) else self.generator, - high_speed_shaft=( - self.high_speed_shaft.as_write() - if isinstance(self.high_speed_shaft, GraphQLCore) - else self.high_speed_shaft - ), - main_shaft=self.main_shaft.as_write() if isinstance(self.main_shaft, GraphQLCore) else self.main_shaft, - power_inverter=( - self.power_inverter.as_write() if isinstance(self.power_inverter, GraphQLCore) else self.power_inverter - ), - yaw_direction=self.yaw_direction.as_write() if self.yaw_direction else None, - yaw_error=self.yaw_error.as_write() if self.yaw_error else None, - ) - - -class Nacelle(DomainModel): - """This represents the reading version of nacelle. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the nacelle. - data_record: The data record of the nacelle node. - acc_from_back_side_x: The acc from back side x field. - acc_from_back_side_y: The acc from back side y field. - acc_from_back_side_z: The acc from back side z field. - gearbox: The gearbox field. - generator: The generator field. - high_speed_shaft: The high speed shaft field. - main_shaft: The main shaft field. - power_inverter: The power inverter field. - yaw_direction: The yaw direction field. - yaw_error: The yaw error field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Nacelle", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - acc_from_back_side_x: Union[TimeSeries, str, None] = None - acc_from_back_side_y: Union[TimeSeries, str, None] = None - acc_from_back_side_z: Union[TimeSeries, str, None] = None - gearbox: Union[Gearbox, str, dm.NodeId, None] = Field(default=None, repr=False) - generator: Union[Generator, str, dm.NodeId, None] = Field(default=None, repr=False) - high_speed_shaft: Union[HighSpeedShaft, str, dm.NodeId, None] = Field(default=None, repr=False) - main_shaft: Union[MainShaft, str, dm.NodeId, None] = Field(default=None, repr=False) - power_inverter: Union[PowerInverter, str, dm.NodeId, None] = Field(default=None, repr=False) - yaw_direction: Union[TimeSeries, str, None] = None - yaw_error: Union[TimeSeries, str, None] = None - - def as_write(self) -> NacelleWrite: - """Convert this read version of nacelle to the writing version.""" - return NacelleWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - acc_from_back_side_x=( - self.acc_from_back_side_x.as_write() - if isinstance(self.acc_from_back_side_x, CogniteTimeSeries) - else self.acc_from_back_side_x - ), - acc_from_back_side_y=( - self.acc_from_back_side_y.as_write() - if isinstance(self.acc_from_back_side_y, CogniteTimeSeries) - else self.acc_from_back_side_y - ), - acc_from_back_side_z=( - self.acc_from_back_side_z.as_write() - if isinstance(self.acc_from_back_side_z, CogniteTimeSeries) - else self.acc_from_back_side_z - ), - gearbox=self.gearbox.as_write() if isinstance(self.gearbox, DomainModel) else self.gearbox, - generator=self.generator.as_write() if isinstance(self.generator, DomainModel) else self.generator, - high_speed_shaft=( - self.high_speed_shaft.as_write() - if isinstance(self.high_speed_shaft, DomainModel) - else self.high_speed_shaft - ), - main_shaft=self.main_shaft.as_write() if isinstance(self.main_shaft, DomainModel) else self.main_shaft, - power_inverter=( - self.power_inverter.as_write() if isinstance(self.power_inverter, DomainModel) else self.power_inverter - ), - yaw_direction=( - self.yaw_direction.as_write() - if isinstance(self.yaw_direction, CogniteTimeSeries) - else self.yaw_direction - ), - yaw_error=self.yaw_error.as_write() if isinstance(self.yaw_error, CogniteTimeSeries) else self.yaw_error, - ) - - def as_apply(self) -> NacelleWrite: - """Convert this read version of nacelle to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - @classmethod - def _update_connections( - cls, - instances: dict[dm.NodeId | str, Nacelle], # type: ignore[override] - nodes_by_id: dict[dm.NodeId | str, DomainModel], - edges_by_source_node: dict[dm.NodeId, list[dm.Edge | DomainRelation]], - ) -> None: - from ._gearbox import Gearbox - from ._generator import Generator - from ._high_speed_shaft import HighSpeedShaft - from ._main_shaft import MainShaft - from ._power_inverter import PowerInverter - - for instance in instances.values(): - if ( - isinstance(instance.gearbox, (dm.NodeId, str)) - and (gearbox := nodes_by_id.get(instance.gearbox)) - and isinstance(gearbox, Gearbox) - ): - instance.gearbox = gearbox - if ( - isinstance(instance.generator, (dm.NodeId, str)) - and (generator := nodes_by_id.get(instance.generator)) - and isinstance(generator, Generator) - ): - instance.generator = generator - if ( - isinstance(instance.high_speed_shaft, (dm.NodeId, str)) - and (high_speed_shaft := nodes_by_id.get(instance.high_speed_shaft)) - and isinstance(high_speed_shaft, HighSpeedShaft) - ): - instance.high_speed_shaft = high_speed_shaft - if ( - isinstance(instance.main_shaft, (dm.NodeId, str)) - and (main_shaft := nodes_by_id.get(instance.main_shaft)) - and isinstance(main_shaft, MainShaft) - ): - instance.main_shaft = main_shaft - if ( - isinstance(instance.power_inverter, (dm.NodeId, str)) - and (power_inverter := nodes_by_id.get(instance.power_inverter)) - and isinstance(power_inverter, PowerInverter) - ): - instance.power_inverter = power_inverter - - -class NacelleWrite(DomainModelWrite): - """This represents the writing version of nacelle. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the nacelle. - data_record: The data record of the nacelle node. - acc_from_back_side_x: The acc from back side x field. - acc_from_back_side_y: The acc from back side y field. - acc_from_back_side_z: The acc from back side z field. - gearbox: The gearbox field. - generator: The generator field. - high_speed_shaft: The high speed shaft field. - main_shaft: The main shaft field. - power_inverter: The power inverter field. - yaw_direction: The yaw direction field. - yaw_error: The yaw error field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Nacelle", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - acc_from_back_side_x: Union[TimeSeriesWrite, str, None] = None - acc_from_back_side_y: Union[TimeSeriesWrite, str, None] = None - acc_from_back_side_z: Union[TimeSeriesWrite, str, None] = None - gearbox: Union[GearboxWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - generator: Union[GeneratorWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - high_speed_shaft: Union[HighSpeedShaftWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - main_shaft: Union[MainShaftWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - power_inverter: Union[PowerInverterWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - yaw_direction: Union[TimeSeriesWrite, str, None] = None - yaw_error: Union[TimeSeriesWrite, str, None] = None - - @field_validator("gearbox", "generator", "high_speed_shaft", "main_shaft", "power_inverter", mode="before") - def as_node_id(cls, value: Any) -> Any: - if isinstance(value, dm.DirectRelationReference): - return dm.NodeId(value.space, value.external_id) - elif isinstance(value, tuple) and len(value) == 2 and all(isinstance(item, str) for item in value): - return dm.NodeId(value[0], value[1]) - elif isinstance(value, list): - return [cls.as_node_id(item) for item in value] - return value - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.acc_from_back_side_x is not None or write_none: - properties["acc_from_back_side_x"] = ( - self.acc_from_back_side_x - if isinstance(self.acc_from_back_side_x, str) or self.acc_from_back_side_x is None - else self.acc_from_back_side_x.external_id - ) - - if self.acc_from_back_side_y is not None or write_none: - properties["acc_from_back_side_y"] = ( - self.acc_from_back_side_y - if isinstance(self.acc_from_back_side_y, str) or self.acc_from_back_side_y is None - else self.acc_from_back_side_y.external_id - ) - - if self.acc_from_back_side_z is not None or write_none: - properties["acc_from_back_side_z"] = ( - self.acc_from_back_side_z - if isinstance(self.acc_from_back_side_z, str) or self.acc_from_back_side_z is None - else self.acc_from_back_side_z.external_id - ) - - if self.gearbox is not None: - properties["gearbox"] = { - "space": self.space if isinstance(self.gearbox, str) else self.gearbox.space, - "externalId": self.gearbox if isinstance(self.gearbox, str) else self.gearbox.external_id, - } - - if self.generator is not None: - properties["generator"] = { - "space": self.space if isinstance(self.generator, str) else self.generator.space, - "externalId": self.generator if isinstance(self.generator, str) else self.generator.external_id, - } - - if self.high_speed_shaft is not None: - properties["high_speed_shaft"] = { - "space": self.space if isinstance(self.high_speed_shaft, str) else self.high_speed_shaft.space, - "externalId": ( - self.high_speed_shaft - if isinstance(self.high_speed_shaft, str) - else self.high_speed_shaft.external_id - ), - } - - if self.main_shaft is not None: - properties["main_shaft"] = { - "space": self.space if isinstance(self.main_shaft, str) else self.main_shaft.space, - "externalId": self.main_shaft if isinstance(self.main_shaft, str) else self.main_shaft.external_id, - } - - if self.power_inverter is not None: - properties["power_inverter"] = { - "space": self.space if isinstance(self.power_inverter, str) else self.power_inverter.space, - "externalId": ( - self.power_inverter if isinstance(self.power_inverter, str) else self.power_inverter.external_id - ), - } - - if self.yaw_direction is not None or write_none: - properties["yaw_direction"] = ( - self.yaw_direction - if isinstance(self.yaw_direction, str) or self.yaw_direction is None - else self.yaw_direction.external_id - ) - - if self.yaw_error is not None or write_none: - properties["yaw_error"] = ( - self.yaw_error - if isinstance(self.yaw_error, str) or self.yaw_error is None - else self.yaw_error.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.gearbox, DomainModelWrite): - other_resources = self.gearbox._to_instances_write(cache) - resources.extend(other_resources) - - if isinstance(self.generator, DomainModelWrite): - other_resources = self.generator._to_instances_write(cache) - resources.extend(other_resources) - - if isinstance(self.high_speed_shaft, DomainModelWrite): - other_resources = self.high_speed_shaft._to_instances_write(cache) - resources.extend(other_resources) - - if isinstance(self.main_shaft, DomainModelWrite): - other_resources = self.main_shaft._to_instances_write(cache) - resources.extend(other_resources) - - if isinstance(self.power_inverter, DomainModelWrite): - other_resources = self.power_inverter._to_instances_write(cache) - resources.extend(other_resources) - - if isinstance(self.acc_from_back_side_x, CogniteTimeSeriesWrite): - resources.time_series.append(self.acc_from_back_side_x) - - if isinstance(self.acc_from_back_side_y, CogniteTimeSeriesWrite): - resources.time_series.append(self.acc_from_back_side_y) - - if isinstance(self.acc_from_back_side_z, CogniteTimeSeriesWrite): - resources.time_series.append(self.acc_from_back_side_z) - - if isinstance(self.yaw_direction, CogniteTimeSeriesWrite): - resources.time_series.append(self.yaw_direction) - - if isinstance(self.yaw_error, CogniteTimeSeriesWrite): - resources.time_series.append(self.yaw_error) - - return resources - - -class NacelleApply(NacelleWrite): - def __new__(cls, *args, **kwargs) -> NacelleApply: - warnings.warn( - "NacelleApply is deprecated and will be removed in v1.0. Use NacelleWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "Nacelle.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class NacelleList(DomainModelList[Nacelle]): - """List of nacelles in the read version.""" - - _INSTANCE = Nacelle - - def as_write(self) -> NacelleWriteList: - """Convert these read versions of nacelle to the writing versions.""" - return NacelleWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> NacelleWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - @property - def gearbox(self) -> GearboxList: - from ._gearbox import Gearbox, GearboxList - - return GearboxList([item.gearbox for item in self.data if isinstance(item.gearbox, Gearbox)]) - - @property - def generator(self) -> GeneratorList: - from ._generator import Generator, GeneratorList - - return GeneratorList([item.generator for item in self.data if isinstance(item.generator, Generator)]) - - @property - def high_speed_shaft(self) -> HighSpeedShaftList: - from ._high_speed_shaft import HighSpeedShaft, HighSpeedShaftList - - return HighSpeedShaftList( - [item.high_speed_shaft for item in self.data if isinstance(item.high_speed_shaft, HighSpeedShaft)] - ) - - @property - def main_shaft(self) -> MainShaftList: - from ._main_shaft import MainShaft, MainShaftList - - return MainShaftList([item.main_shaft for item in self.data if isinstance(item.main_shaft, MainShaft)]) - - @property - def power_inverter(self) -> PowerInverterList: - from ._power_inverter import PowerInverter, PowerInverterList - - return PowerInverterList( - [item.power_inverter for item in self.data if isinstance(item.power_inverter, PowerInverter)] - ) - - -class NacelleWriteList(DomainModelWriteList[NacelleWrite]): - """List of nacelles in the writing version.""" - - _INSTANCE = NacelleWrite - - @property - def gearbox(self) -> GearboxWriteList: - from ._gearbox import GearboxWrite, GearboxWriteList - - return GearboxWriteList([item.gearbox for item in self.data if isinstance(item.gearbox, GearboxWrite)]) - - @property - def generator(self) -> GeneratorWriteList: - from ._generator import GeneratorWrite, GeneratorWriteList - - return GeneratorWriteList([item.generator for item in self.data if isinstance(item.generator, GeneratorWrite)]) - - @property - def high_speed_shaft(self) -> HighSpeedShaftWriteList: - from ._high_speed_shaft import HighSpeedShaftWrite, HighSpeedShaftWriteList - - return HighSpeedShaftWriteList( - [item.high_speed_shaft for item in self.data if isinstance(item.high_speed_shaft, HighSpeedShaftWrite)] - ) - - @property - def main_shaft(self) -> MainShaftWriteList: - from ._main_shaft import MainShaftWrite, MainShaftWriteList - - return MainShaftWriteList( - [item.main_shaft for item in self.data if isinstance(item.main_shaft, MainShaftWrite)] - ) - - @property - def power_inverter(self) -> PowerInverterWriteList: - from ._power_inverter import PowerInverterWrite, PowerInverterWriteList - - return PowerInverterWriteList( - [item.power_inverter for item in self.data if isinstance(item.power_inverter, PowerInverterWrite)] - ) - - -class NacelleApplyList(NacelleWriteList): ... - - -def _create_nacelle_filter( - view_id: dm.ViewId, - gearbox: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - generator: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - high_speed_shaft: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - main_shaft: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - power_inverter: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if isinstance(gearbox, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(gearbox): - filters.append(dm.filters.Equals(view_id.as_property_ref("gearbox"), value=as_instance_dict_id(gearbox))) - if gearbox and isinstance(gearbox, Sequence) and not isinstance(gearbox, str) and not is_tuple_id(gearbox): - filters.append( - dm.filters.In(view_id.as_property_ref("gearbox"), values=[as_instance_dict_id(item) for item in gearbox]) - ) - if isinstance(generator, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(generator): - filters.append(dm.filters.Equals(view_id.as_property_ref("generator"), value=as_instance_dict_id(generator))) - if generator and isinstance(generator, Sequence) and not isinstance(generator, str) and not is_tuple_id(generator): - filters.append( - dm.filters.In( - view_id.as_property_ref("generator"), values=[as_instance_dict_id(item) for item in generator] - ) - ) - if isinstance(high_speed_shaft, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(high_speed_shaft): - filters.append( - dm.filters.Equals(view_id.as_property_ref("high_speed_shaft"), value=as_instance_dict_id(high_speed_shaft)) - ) - if ( - high_speed_shaft - and isinstance(high_speed_shaft, Sequence) - and not isinstance(high_speed_shaft, str) - and not is_tuple_id(high_speed_shaft) - ): - filters.append( - dm.filters.In( - view_id.as_property_ref("high_speed_shaft"), - values=[as_instance_dict_id(item) for item in high_speed_shaft], - ) - ) - if isinstance(main_shaft, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(main_shaft): - filters.append(dm.filters.Equals(view_id.as_property_ref("main_shaft"), value=as_instance_dict_id(main_shaft))) - if ( - main_shaft - and isinstance(main_shaft, Sequence) - and not isinstance(main_shaft, str) - and not is_tuple_id(main_shaft) - ): - filters.append( - dm.filters.In( - view_id.as_property_ref("main_shaft"), values=[as_instance_dict_id(item) for item in main_shaft] - ) - ) - if isinstance(power_inverter, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(power_inverter): - filters.append( - dm.filters.Equals(view_id.as_property_ref("power_inverter"), value=as_instance_dict_id(power_inverter)) - ) - if ( - power_inverter - and isinstance(power_inverter, Sequence) - and not isinstance(power_inverter, str) - and not is_tuple_id(power_inverter) - ): - filters.append( - dm.filters.In( - view_id.as_property_ref("power_inverter"), values=[as_instance_dict_id(item) for item in power_inverter] - ) - ) - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _NacelleQuery(NodeQueryCore[T_DomainModelList, NacelleList]): - _view_id = Nacelle._view_id - _result_cls = Nacelle - _result_list_cls_end = NacelleList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - from ._gearbox import _GearboxQuery - from ._generator import _GeneratorQuery - from ._high_speed_shaft import _HighSpeedShaftQuery - from ._main_shaft import _MainShaftQuery - from ._power_inverter import _PowerInverterQuery - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - if _GearboxQuery not in created_types: - self.gearbox = _GearboxQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("gearbox"), - direction="outwards", - ), - connection_name="gearbox", - ) - - if _GeneratorQuery not in created_types: - self.generator = _GeneratorQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("generator"), - direction="outwards", - ), - connection_name="generator", - ) - - if _HighSpeedShaftQuery not in created_types: - self.high_speed_shaft = _HighSpeedShaftQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("high_speed_shaft"), - direction="outwards", - ), - connection_name="high_speed_shaft", - ) - - if _MainShaftQuery not in created_types: - self.main_shaft = _MainShaftQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("main_shaft"), - direction="outwards", - ), - connection_name="main_shaft", - ) - - if _PowerInverterQuery not in created_types: - self.power_inverter = _PowerInverterQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("power_inverter"), - direction="outwards", - ), - connection_name="power_inverter", - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_nacelle(self, limit: int = DEFAULT_QUERY_LIMIT) -> NacelleList: - return self._list(limit=limit) - - -class NacelleQuery(_NacelleQuery[NacelleList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, NacelleList) diff --git a/examples/windmill/data_classes/_power_inverter.py b/examples/windmill/data_classes/_power_inverter.py deleted file mode 100644 index 290c7e181..000000000 --- a/examples/windmill/data_classes/_power_inverter.py +++ /dev/null @@ -1,370 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - - -__all__ = [ - "PowerInverter", - "PowerInverterWrite", - "PowerInverterApply", - "PowerInverterList", - "PowerInverterWriteList", - "PowerInverterApplyList", - "PowerInverterFields", - "PowerInverterTextFields", - "PowerInverterGraphQL", -] - - -PowerInverterTextFields = Literal["external_id", "active_power_total", "apparent_power_total", "reactive_power_total"] -PowerInverterFields = Literal["external_id", "active_power_total", "apparent_power_total", "reactive_power_total"] - -_POWERINVERTER_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "active_power_total": "active_power_total", - "apparent_power_total": "apparent_power_total", - "reactive_power_total": "reactive_power_total", -} - - -class PowerInverterGraphQL(GraphQLCore): - """This represents the reading version of power inverter, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the power inverter. - data_record: The data record of the power inverter node. - active_power_total: The active power total field. - apparent_power_total: The apparent power total field. - reactive_power_total: The reactive power total field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "PowerInverter", "1") - active_power_total: Optional[TimeSeriesGraphQL] = None - apparent_power_total: Optional[TimeSeriesGraphQL] = None - reactive_power_total: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> PowerInverter: - """Convert this GraphQL format of power inverter to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return PowerInverter( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - active_power_total=self.active_power_total.as_read() if self.active_power_total else None, - apparent_power_total=self.apparent_power_total.as_read() if self.apparent_power_total else None, - reactive_power_total=self.reactive_power_total.as_read() if self.reactive_power_total else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> PowerInverterWrite: - """Convert this GraphQL format of power inverter to the writing format.""" - return PowerInverterWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - active_power_total=self.active_power_total.as_write() if self.active_power_total else None, - apparent_power_total=self.apparent_power_total.as_write() if self.apparent_power_total else None, - reactive_power_total=self.reactive_power_total.as_write() if self.reactive_power_total else None, - ) - - -class PowerInverter(DomainModel): - """This represents the reading version of power inverter. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the power inverter. - data_record: The data record of the power inverter node. - active_power_total: The active power total field. - apparent_power_total: The apparent power total field. - reactive_power_total: The reactive power total field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "PowerInverter", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - active_power_total: Union[TimeSeries, str, None] = None - apparent_power_total: Union[TimeSeries, str, None] = None - reactive_power_total: Union[TimeSeries, str, None] = None - - def as_write(self) -> PowerInverterWrite: - """Convert this read version of power inverter to the writing version.""" - return PowerInverterWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - active_power_total=( - self.active_power_total.as_write() - if isinstance(self.active_power_total, CogniteTimeSeries) - else self.active_power_total - ), - apparent_power_total=( - self.apparent_power_total.as_write() - if isinstance(self.apparent_power_total, CogniteTimeSeries) - else self.apparent_power_total - ), - reactive_power_total=( - self.reactive_power_total.as_write() - if isinstance(self.reactive_power_total, CogniteTimeSeries) - else self.reactive_power_total - ), - ) - - def as_apply(self) -> PowerInverterWrite: - """Convert this read version of power inverter to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class PowerInverterWrite(DomainModelWrite): - """This represents the writing version of power inverter. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the power inverter. - data_record: The data record of the power inverter node. - active_power_total: The active power total field. - apparent_power_total: The apparent power total field. - reactive_power_total: The reactive power total field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "PowerInverter", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - active_power_total: Union[TimeSeriesWrite, str, None] = None - apparent_power_total: Union[TimeSeriesWrite, str, None] = None - reactive_power_total: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.active_power_total is not None or write_none: - properties["active_power_total"] = ( - self.active_power_total - if isinstance(self.active_power_total, str) or self.active_power_total is None - else self.active_power_total.external_id - ) - - if self.apparent_power_total is not None or write_none: - properties["apparent_power_total"] = ( - self.apparent_power_total - if isinstance(self.apparent_power_total, str) or self.apparent_power_total is None - else self.apparent_power_total.external_id - ) - - if self.reactive_power_total is not None or write_none: - properties["reactive_power_total"] = ( - self.reactive_power_total - if isinstance(self.reactive_power_total, str) or self.reactive_power_total is None - else self.reactive_power_total.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.active_power_total, CogniteTimeSeriesWrite): - resources.time_series.append(self.active_power_total) - - if isinstance(self.apparent_power_total, CogniteTimeSeriesWrite): - resources.time_series.append(self.apparent_power_total) - - if isinstance(self.reactive_power_total, CogniteTimeSeriesWrite): - resources.time_series.append(self.reactive_power_total) - - return resources - - -class PowerInverterApply(PowerInverterWrite): - def __new__(cls, *args, **kwargs) -> PowerInverterApply: - warnings.warn( - "PowerInverterApply is deprecated and will be removed in v1.0. Use PowerInverterWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "PowerInverter.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class PowerInverterList(DomainModelList[PowerInverter]): - """List of power inverters in the read version.""" - - _INSTANCE = PowerInverter - - def as_write(self) -> PowerInverterWriteList: - """Convert these read versions of power inverter to the writing versions.""" - return PowerInverterWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> PowerInverterWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class PowerInverterWriteList(DomainModelWriteList[PowerInverterWrite]): - """List of power inverters in the writing version.""" - - _INSTANCE = PowerInverterWrite - - -class PowerInverterApplyList(PowerInverterWriteList): ... - - -def _create_power_inverter_filter( - view_id: dm.ViewId, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _PowerInverterQuery(NodeQueryCore[T_DomainModelList, PowerInverterList]): - _view_id = PowerInverter._view_id - _result_cls = PowerInverter - _result_list_cls_end = PowerInverterList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_power_inverter(self, limit: int = DEFAULT_QUERY_LIMIT) -> PowerInverterList: - return self._list(limit=limit) - - -class PowerInverterQuery(_PowerInverterQuery[PowerInverterList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, PowerInverterList) diff --git a/examples/windmill/data_classes/_rotor.py b/examples/windmill/data_classes/_rotor.py deleted file mode 100644 index 34fdcb12a..000000000 --- a/examples/windmill/data_classes/_rotor.py +++ /dev/null @@ -1,346 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, -) - - -__all__ = [ - "Rotor", - "RotorWrite", - "RotorApply", - "RotorList", - "RotorWriteList", - "RotorApplyList", - "RotorFields", - "RotorTextFields", - "RotorGraphQL", -] - - -RotorTextFields = Literal["external_id", "rotor_speed_controller", "rpm_low_speed_shaft"] -RotorFields = Literal["external_id", "rotor_speed_controller", "rpm_low_speed_shaft"] - -_ROTOR_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "rotor_speed_controller": "rotor_speed_controller", - "rpm_low_speed_shaft": "rpm_low_speed_shaft", -} - - -class RotorGraphQL(GraphQLCore): - """This represents the reading version of rotor, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the rotor. - data_record: The data record of the rotor node. - rotor_speed_controller: The rotor speed controller field. - rpm_low_speed_shaft: The rpm low speed shaft field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Rotor", "1") - rotor_speed_controller: Optional[TimeSeriesGraphQL] = None - rpm_low_speed_shaft: Optional[TimeSeriesGraphQL] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> Rotor: - """Convert this GraphQL format of rotor to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return Rotor( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - rotor_speed_controller=self.rotor_speed_controller.as_read() if self.rotor_speed_controller else None, - rpm_low_speed_shaft=self.rpm_low_speed_shaft.as_read() if self.rpm_low_speed_shaft else None, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> RotorWrite: - """Convert this GraphQL format of rotor to the writing format.""" - return RotorWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - rotor_speed_controller=self.rotor_speed_controller.as_write() if self.rotor_speed_controller else None, - rpm_low_speed_shaft=self.rpm_low_speed_shaft.as_write() if self.rpm_low_speed_shaft else None, - ) - - -class Rotor(DomainModel): - """This represents the reading version of rotor. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the rotor. - data_record: The data record of the rotor node. - rotor_speed_controller: The rotor speed controller field. - rpm_low_speed_shaft: The rpm low speed shaft field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Rotor", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - rotor_speed_controller: Union[TimeSeries, str, None] = None - rpm_low_speed_shaft: Union[TimeSeries, str, None] = None - - def as_write(self) -> RotorWrite: - """Convert this read version of rotor to the writing version.""" - return RotorWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - rotor_speed_controller=( - self.rotor_speed_controller.as_write() - if isinstance(self.rotor_speed_controller, CogniteTimeSeries) - else self.rotor_speed_controller - ), - rpm_low_speed_shaft=( - self.rpm_low_speed_shaft.as_write() - if isinstance(self.rpm_low_speed_shaft, CogniteTimeSeries) - else self.rpm_low_speed_shaft - ), - ) - - def as_apply(self) -> RotorWrite: - """Convert this read version of rotor to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class RotorWrite(DomainModelWrite): - """This represents the writing version of rotor. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the rotor. - data_record: The data record of the rotor node. - rotor_speed_controller: The rotor speed controller field. - rpm_low_speed_shaft: The rpm low speed shaft field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Rotor", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - rotor_speed_controller: Union[TimeSeriesWrite, str, None] = None - rpm_low_speed_shaft: Union[TimeSeriesWrite, str, None] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.rotor_speed_controller is not None or write_none: - properties["rotor_speed_controller"] = ( - self.rotor_speed_controller - if isinstance(self.rotor_speed_controller, str) or self.rotor_speed_controller is None - else self.rotor_speed_controller.external_id - ) - - if self.rpm_low_speed_shaft is not None or write_none: - properties["rpm_low_speed_shaft"] = ( - self.rpm_low_speed_shaft - if isinstance(self.rpm_low_speed_shaft, str) or self.rpm_low_speed_shaft is None - else self.rpm_low_speed_shaft.external_id - ) - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.rotor_speed_controller, CogniteTimeSeriesWrite): - resources.time_series.append(self.rotor_speed_controller) - - if isinstance(self.rpm_low_speed_shaft, CogniteTimeSeriesWrite): - resources.time_series.append(self.rpm_low_speed_shaft) - - return resources - - -class RotorApply(RotorWrite): - def __new__(cls, *args, **kwargs) -> RotorApply: - warnings.warn( - "RotorApply is deprecated and will be removed in v1.0. Use RotorWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "Rotor.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class RotorList(DomainModelList[Rotor]): - """List of rotors in the read version.""" - - _INSTANCE = Rotor - - def as_write(self) -> RotorWriteList: - """Convert these read versions of rotor to the writing versions.""" - return RotorWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> RotorWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class RotorWriteList(DomainModelWriteList[RotorWrite]): - """List of rotors in the writing version.""" - - _INSTANCE = RotorWrite - - -class RotorApplyList(RotorWriteList): ... - - -def _create_rotor_filter( - view_id: dm.ViewId, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _RotorQuery(NodeQueryCore[T_DomainModelList, RotorList]): - _view_id = Rotor._view_id - _result_cls = Rotor - _result_list_cls_end = RotorList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - - def list_rotor(self, limit: int = DEFAULT_QUERY_LIMIT) -> RotorList: - return self._list(limit=limit) - - -class RotorQuery(_RotorQuery[RotorList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, RotorList) diff --git a/examples/windmill/data_classes/_sensor_position.py b/examples/windmill/data_classes/_sensor_position.py deleted file mode 100644 index 2e7d7032c..000000000 --- a/examples/windmill/data_classes/_sensor_position.py +++ /dev/null @@ -1,577 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from cognite.client.data_classes import ( - TimeSeries as CogniteTimeSeries, - TimeSeriesWrite as CogniteTimeSeriesWrite, -) -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - FileMetadata, - FileMetadataWrite, - FileMetadataGraphQL, - TimeSeries, - TimeSeriesWrite, - TimeSeriesGraphQL, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, - FloatFilter, -) - - -__all__ = [ - "SensorPosition", - "SensorPositionWrite", - "SensorPositionApply", - "SensorPositionList", - "SensorPositionWriteList", - "SensorPositionApplyList", - "SensorPositionFields", - "SensorPositionTextFields", - "SensorPositionGraphQL", -] - - -SensorPositionTextFields = Literal[ - "external_id", - "edgewise_bend_mom_crosstalk_corrected", - "edgewise_bend_mom_offset", - "edgewise_bend_mom_offset_crosstalk_corrected", - "edgewisewise_bend_mom", - "flapwise_bend_mom", - "flapwise_bend_mom_crosstalk_corrected", - "flapwise_bend_mom_offset", - "flapwise_bend_mom_offset_crosstalk_corrected", -] -SensorPositionFields = Literal[ - "external_id", - "edgewise_bend_mom_crosstalk_corrected", - "edgewise_bend_mom_offset", - "edgewise_bend_mom_offset_crosstalk_corrected", - "edgewisewise_bend_mom", - "flapwise_bend_mom", - "flapwise_bend_mom_crosstalk_corrected", - "flapwise_bend_mom_offset", - "flapwise_bend_mom_offset_crosstalk_corrected", - "position", -] - -_SENSORPOSITION_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "edgewise_bend_mom_crosstalk_corrected": "edgewise_bend_mom_crosstalk_corrected", - "edgewise_bend_mom_offset": "edgewise_bend_mom_offset", - "edgewise_bend_mom_offset_crosstalk_corrected": "edgewise_bend_mom_offset_crosstalk_corrected", - "edgewisewise_bend_mom": "edgewisewise_bend_mom", - "flapwise_bend_mom": "flapwise_bend_mom", - "flapwise_bend_mom_crosstalk_corrected": "flapwise_bend_mom_crosstalk_corrected", - "flapwise_bend_mom_offset": "flapwise_bend_mom_offset", - "flapwise_bend_mom_offset_crosstalk_corrected": "flapwise_bend_mom_offset_crosstalk_corrected", - "position": "position", -} - - -class SensorPositionGraphQL(GraphQLCore): - """This represents the reading version of sensor position, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the sensor position. - data_record: The data record of the sensor position node. - edgewise_bend_mom_crosstalk_corrected: The edgewise bend mom crosstalk corrected field. - edgewise_bend_mom_offset: The edgewise bend mom offset field. - edgewise_bend_mom_offset_crosstalk_corrected: The edgewise bend mom offset crosstalk corrected field. - edgewisewise_bend_mom: The edgewisewise bend mom field. - flapwise_bend_mom: The flapwise bend mom field. - flapwise_bend_mom_crosstalk_corrected: The flapwise bend mom crosstalk corrected field. - flapwise_bend_mom_offset: The flapwise bend mom offset field. - flapwise_bend_mom_offset_crosstalk_corrected: The flapwise bend mom offset crosstalk corrected field. - position: The position field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "SensorPosition", "1") - edgewise_bend_mom_crosstalk_corrected: Optional[TimeSeriesGraphQL] = None - edgewise_bend_mom_offset: Optional[TimeSeriesGraphQL] = None - edgewise_bend_mom_offset_crosstalk_corrected: Optional[TimeSeriesGraphQL] = None - edgewisewise_bend_mom: Optional[TimeSeriesGraphQL] = None - flapwise_bend_mom: Optional[TimeSeriesGraphQL] = None - flapwise_bend_mom_crosstalk_corrected: Optional[TimeSeriesGraphQL] = None - flapwise_bend_mom_offset: Optional[TimeSeriesGraphQL] = None - flapwise_bend_mom_offset_crosstalk_corrected: Optional[TimeSeriesGraphQL] = None - position: Optional[float] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> SensorPosition: - """Convert this GraphQL format of sensor position to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return SensorPosition( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - edgewise_bend_mom_crosstalk_corrected=( - self.edgewise_bend_mom_crosstalk_corrected.as_read() - if self.edgewise_bend_mom_crosstalk_corrected - else None - ), - edgewise_bend_mom_offset=self.edgewise_bend_mom_offset.as_read() if self.edgewise_bend_mom_offset else None, - edgewise_bend_mom_offset_crosstalk_corrected=( - self.edgewise_bend_mom_offset_crosstalk_corrected.as_read() - if self.edgewise_bend_mom_offset_crosstalk_corrected - else None - ), - edgewisewise_bend_mom=self.edgewisewise_bend_mom.as_read() if self.edgewisewise_bend_mom else None, - flapwise_bend_mom=self.flapwise_bend_mom.as_read() if self.flapwise_bend_mom else None, - flapwise_bend_mom_crosstalk_corrected=( - self.flapwise_bend_mom_crosstalk_corrected.as_read() - if self.flapwise_bend_mom_crosstalk_corrected - else None - ), - flapwise_bend_mom_offset=self.flapwise_bend_mom_offset.as_read() if self.flapwise_bend_mom_offset else None, - flapwise_bend_mom_offset_crosstalk_corrected=( - self.flapwise_bend_mom_offset_crosstalk_corrected.as_read() - if self.flapwise_bend_mom_offset_crosstalk_corrected - else None - ), - position=self.position, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> SensorPositionWrite: - """Convert this GraphQL format of sensor position to the writing format.""" - return SensorPositionWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - edgewise_bend_mom_crosstalk_corrected=( - self.edgewise_bend_mom_crosstalk_corrected.as_write() - if self.edgewise_bend_mom_crosstalk_corrected - else None - ), - edgewise_bend_mom_offset=( - self.edgewise_bend_mom_offset.as_write() if self.edgewise_bend_mom_offset else None - ), - edgewise_bend_mom_offset_crosstalk_corrected=( - self.edgewise_bend_mom_offset_crosstalk_corrected.as_write() - if self.edgewise_bend_mom_offset_crosstalk_corrected - else None - ), - edgewisewise_bend_mom=self.edgewisewise_bend_mom.as_write() if self.edgewisewise_bend_mom else None, - flapwise_bend_mom=self.flapwise_bend_mom.as_write() if self.flapwise_bend_mom else None, - flapwise_bend_mom_crosstalk_corrected=( - self.flapwise_bend_mom_crosstalk_corrected.as_write() - if self.flapwise_bend_mom_crosstalk_corrected - else None - ), - flapwise_bend_mom_offset=( - self.flapwise_bend_mom_offset.as_write() if self.flapwise_bend_mom_offset else None - ), - flapwise_bend_mom_offset_crosstalk_corrected=( - self.flapwise_bend_mom_offset_crosstalk_corrected.as_write() - if self.flapwise_bend_mom_offset_crosstalk_corrected - else None - ), - position=self.position, - ) - - -class SensorPosition(DomainModel): - """This represents the reading version of sensor position. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the sensor position. - data_record: The data record of the sensor position node. - edgewise_bend_mom_crosstalk_corrected: The edgewise bend mom crosstalk corrected field. - edgewise_bend_mom_offset: The edgewise bend mom offset field. - edgewise_bend_mom_offset_crosstalk_corrected: The edgewise bend mom offset crosstalk corrected field. - edgewisewise_bend_mom: The edgewisewise bend mom field. - flapwise_bend_mom: The flapwise bend mom field. - flapwise_bend_mom_crosstalk_corrected: The flapwise bend mom crosstalk corrected field. - flapwise_bend_mom_offset: The flapwise bend mom offset field. - flapwise_bend_mom_offset_crosstalk_corrected: The flapwise bend mom offset crosstalk corrected field. - position: The position field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "SensorPosition", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - edgewise_bend_mom_crosstalk_corrected: Union[TimeSeries, str, None] = None - edgewise_bend_mom_offset: Union[TimeSeries, str, None] = None - edgewise_bend_mom_offset_crosstalk_corrected: Union[TimeSeries, str, None] = None - edgewisewise_bend_mom: Union[TimeSeries, str, None] = None - flapwise_bend_mom: Union[TimeSeries, str, None] = None - flapwise_bend_mom_crosstalk_corrected: Union[TimeSeries, str, None] = None - flapwise_bend_mom_offset: Union[TimeSeries, str, None] = None - flapwise_bend_mom_offset_crosstalk_corrected: Union[TimeSeries, str, None] = None - position: Optional[float] = None - - def as_write(self) -> SensorPositionWrite: - """Convert this read version of sensor position to the writing version.""" - return SensorPositionWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - edgewise_bend_mom_crosstalk_corrected=( - self.edgewise_bend_mom_crosstalk_corrected.as_write() - if isinstance(self.edgewise_bend_mom_crosstalk_corrected, CogniteTimeSeries) - else self.edgewise_bend_mom_crosstalk_corrected - ), - edgewise_bend_mom_offset=( - self.edgewise_bend_mom_offset.as_write() - if isinstance(self.edgewise_bend_mom_offset, CogniteTimeSeries) - else self.edgewise_bend_mom_offset - ), - edgewise_bend_mom_offset_crosstalk_corrected=( - self.edgewise_bend_mom_offset_crosstalk_corrected.as_write() - if isinstance(self.edgewise_bend_mom_offset_crosstalk_corrected, CogniteTimeSeries) - else self.edgewise_bend_mom_offset_crosstalk_corrected - ), - edgewisewise_bend_mom=( - self.edgewisewise_bend_mom.as_write() - if isinstance(self.edgewisewise_bend_mom, CogniteTimeSeries) - else self.edgewisewise_bend_mom - ), - flapwise_bend_mom=( - self.flapwise_bend_mom.as_write() - if isinstance(self.flapwise_bend_mom, CogniteTimeSeries) - else self.flapwise_bend_mom - ), - flapwise_bend_mom_crosstalk_corrected=( - self.flapwise_bend_mom_crosstalk_corrected.as_write() - if isinstance(self.flapwise_bend_mom_crosstalk_corrected, CogniteTimeSeries) - else self.flapwise_bend_mom_crosstalk_corrected - ), - flapwise_bend_mom_offset=( - self.flapwise_bend_mom_offset.as_write() - if isinstance(self.flapwise_bend_mom_offset, CogniteTimeSeries) - else self.flapwise_bend_mom_offset - ), - flapwise_bend_mom_offset_crosstalk_corrected=( - self.flapwise_bend_mom_offset_crosstalk_corrected.as_write() - if isinstance(self.flapwise_bend_mom_offset_crosstalk_corrected, CogniteTimeSeries) - else self.flapwise_bend_mom_offset_crosstalk_corrected - ), - position=self.position, - ) - - def as_apply(self) -> SensorPositionWrite: - """Convert this read version of sensor position to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class SensorPositionWrite(DomainModelWrite): - """This represents the writing version of sensor position. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the sensor position. - data_record: The data record of the sensor position node. - edgewise_bend_mom_crosstalk_corrected: The edgewise bend mom crosstalk corrected field. - edgewise_bend_mom_offset: The edgewise bend mom offset field. - edgewise_bend_mom_offset_crosstalk_corrected: The edgewise bend mom offset crosstalk corrected field. - edgewisewise_bend_mom: The edgewisewise bend mom field. - flapwise_bend_mom: The flapwise bend mom field. - flapwise_bend_mom_crosstalk_corrected: The flapwise bend mom crosstalk corrected field. - flapwise_bend_mom_offset: The flapwise bend mom offset field. - flapwise_bend_mom_offset_crosstalk_corrected: The flapwise bend mom offset crosstalk corrected field. - position: The position field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "SensorPosition", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - edgewise_bend_mom_crosstalk_corrected: Union[TimeSeriesWrite, str, None] = None - edgewise_bend_mom_offset: Union[TimeSeriesWrite, str, None] = None - edgewise_bend_mom_offset_crosstalk_corrected: Union[TimeSeriesWrite, str, None] = None - edgewisewise_bend_mom: Union[TimeSeriesWrite, str, None] = None - flapwise_bend_mom: Union[TimeSeriesWrite, str, None] = None - flapwise_bend_mom_crosstalk_corrected: Union[TimeSeriesWrite, str, None] = None - flapwise_bend_mom_offset: Union[TimeSeriesWrite, str, None] = None - flapwise_bend_mom_offset_crosstalk_corrected: Union[TimeSeriesWrite, str, None] = None - position: Optional[float] = None - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.edgewise_bend_mom_crosstalk_corrected is not None or write_none: - properties["edgewise_bend_mom_crosstalk_corrected"] = ( - self.edgewise_bend_mom_crosstalk_corrected - if isinstance(self.edgewise_bend_mom_crosstalk_corrected, str) - or self.edgewise_bend_mom_crosstalk_corrected is None - else self.edgewise_bend_mom_crosstalk_corrected.external_id - ) - - if self.edgewise_bend_mom_offset is not None or write_none: - properties["edgewise_bend_mom_offset"] = ( - self.edgewise_bend_mom_offset - if isinstance(self.edgewise_bend_mom_offset, str) or self.edgewise_bend_mom_offset is None - else self.edgewise_bend_mom_offset.external_id - ) - - if self.edgewise_bend_mom_offset_crosstalk_corrected is not None or write_none: - properties["edgewise_bend_mom_offset_crosstalk_corrected"] = ( - self.edgewise_bend_mom_offset_crosstalk_corrected - if isinstance(self.edgewise_bend_mom_offset_crosstalk_corrected, str) - or self.edgewise_bend_mom_offset_crosstalk_corrected is None - else self.edgewise_bend_mom_offset_crosstalk_corrected.external_id - ) - - if self.edgewisewise_bend_mom is not None or write_none: - properties["edgewisewise_bend_mom"] = ( - self.edgewisewise_bend_mom - if isinstance(self.edgewisewise_bend_mom, str) or self.edgewisewise_bend_mom is None - else self.edgewisewise_bend_mom.external_id - ) - - if self.flapwise_bend_mom is not None or write_none: - properties["flapwise_bend_mom"] = ( - self.flapwise_bend_mom - if isinstance(self.flapwise_bend_mom, str) or self.flapwise_bend_mom is None - else self.flapwise_bend_mom.external_id - ) - - if self.flapwise_bend_mom_crosstalk_corrected is not None or write_none: - properties["flapwise_bend_mom_crosstalk_corrected"] = ( - self.flapwise_bend_mom_crosstalk_corrected - if isinstance(self.flapwise_bend_mom_crosstalk_corrected, str) - or self.flapwise_bend_mom_crosstalk_corrected is None - else self.flapwise_bend_mom_crosstalk_corrected.external_id - ) - - if self.flapwise_bend_mom_offset is not None or write_none: - properties["flapwise_bend_mom_offset"] = ( - self.flapwise_bend_mom_offset - if isinstance(self.flapwise_bend_mom_offset, str) or self.flapwise_bend_mom_offset is None - else self.flapwise_bend_mom_offset.external_id - ) - - if self.flapwise_bend_mom_offset_crosstalk_corrected is not None or write_none: - properties["flapwise_bend_mom_offset_crosstalk_corrected"] = ( - self.flapwise_bend_mom_offset_crosstalk_corrected - if isinstance(self.flapwise_bend_mom_offset_crosstalk_corrected, str) - or self.flapwise_bend_mom_offset_crosstalk_corrected is None - else self.flapwise_bend_mom_offset_crosstalk_corrected.external_id - ) - - if self.position is not None or write_none: - properties["position"] = self.position - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - if isinstance(self.edgewise_bend_mom_crosstalk_corrected, CogniteTimeSeriesWrite): - resources.time_series.append(self.edgewise_bend_mom_crosstalk_corrected) - - if isinstance(self.edgewise_bend_mom_offset, CogniteTimeSeriesWrite): - resources.time_series.append(self.edgewise_bend_mom_offset) - - if isinstance(self.edgewise_bend_mom_offset_crosstalk_corrected, CogniteTimeSeriesWrite): - resources.time_series.append(self.edgewise_bend_mom_offset_crosstalk_corrected) - - if isinstance(self.edgewisewise_bend_mom, CogniteTimeSeriesWrite): - resources.time_series.append(self.edgewisewise_bend_mom) - - if isinstance(self.flapwise_bend_mom, CogniteTimeSeriesWrite): - resources.time_series.append(self.flapwise_bend_mom) - - if isinstance(self.flapwise_bend_mom_crosstalk_corrected, CogniteTimeSeriesWrite): - resources.time_series.append(self.flapwise_bend_mom_crosstalk_corrected) - - if isinstance(self.flapwise_bend_mom_offset, CogniteTimeSeriesWrite): - resources.time_series.append(self.flapwise_bend_mom_offset) - - if isinstance(self.flapwise_bend_mom_offset_crosstalk_corrected, CogniteTimeSeriesWrite): - resources.time_series.append(self.flapwise_bend_mom_offset_crosstalk_corrected) - - return resources - - -class SensorPositionApply(SensorPositionWrite): - def __new__(cls, *args, **kwargs) -> SensorPositionApply: - warnings.warn( - "SensorPositionApply is deprecated and will be removed in v1.0. Use SensorPositionWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "SensorPosition.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class SensorPositionList(DomainModelList[SensorPosition]): - """List of sensor positions in the read version.""" - - _INSTANCE = SensorPosition - - def as_write(self) -> SensorPositionWriteList: - """Convert these read versions of sensor position to the writing versions.""" - return SensorPositionWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> SensorPositionWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - -class SensorPositionWriteList(DomainModelWriteList[SensorPositionWrite]): - """List of sensor positions in the writing version.""" - - _INSTANCE = SensorPositionWrite - - -class SensorPositionApplyList(SensorPositionWriteList): ... - - -def _create_sensor_position_filter( - view_id: dm.ViewId, - min_position: float | None = None, - max_position: float | None = None, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if min_position is not None or max_position is not None: - filters.append(dm.filters.Range(view_id.as_property_ref("position"), gte=min_position, lte=max_position)) - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _SensorPositionQuery(NodeQueryCore[T_DomainModelList, SensorPositionList]): - _view_id = SensorPosition._view_id - _result_cls = SensorPosition - _result_list_cls_end = SensorPositionList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - self.position = FloatFilter(self, self._view_id.as_property_ref("position")) - self._filter_classes.extend( - [ - self.space, - self.external_id, - self.position, - ] - ) - - def list_sensor_position(self, limit: int = DEFAULT_QUERY_LIMIT) -> SensorPositionList: - return self._list(limit=limit) - - -class SensorPositionQuery(_SensorPositionQuery[SensorPositionList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, SensorPositionList) diff --git a/examples/windmill/data_classes/_windmill.py b/examples/windmill/data_classes/_windmill.py deleted file mode 100644 index c7010e195..000000000 --- a/examples/windmill/data_classes/_windmill.py +++ /dev/null @@ -1,665 +0,0 @@ -from __future__ import annotations - -import warnings -from collections.abc import Sequence -from typing import TYPE_CHECKING, Any, ClassVar, Literal, no_type_check, Optional, Union - -from cognite.client import data_modeling as dm, CogniteClient -from pydantic import Field -from pydantic import field_validator, model_validator - -from windmill.data_classes._core import ( - DEFAULT_INSTANCE_SPACE, - DEFAULT_QUERY_LIMIT, - DataRecord, - DataRecordGraphQL, - DataRecordWrite, - DomainModel, - DomainModelWrite, - DomainModelWriteList, - DomainModelList, - DomainRelation, - DomainRelationWrite, - GraphQLCore, - ResourcesWrite, - T_DomainModelList, - as_direct_relation_reference, - as_instance_dict_id, - as_node_id, - as_pygen_node_id, - are_nodes_equal, - is_tuple_id, - select_best_node, - QueryCore, - NodeQueryCore, - StringFilter, - FloatFilter, -) - -if TYPE_CHECKING: - from windmill.data_classes._blade import Blade, BladeList, BladeGraphQL, BladeWrite, BladeWriteList - from windmill.data_classes._metmast import Metmast, MetmastList, MetmastGraphQL, MetmastWrite, MetmastWriteList - from windmill.data_classes._nacelle import Nacelle, NacelleList, NacelleGraphQL, NacelleWrite, NacelleWriteList - from windmill.data_classes._rotor import Rotor, RotorList, RotorGraphQL, RotorWrite, RotorWriteList - - -__all__ = [ - "Windmill", - "WindmillWrite", - "WindmillApply", - "WindmillList", - "WindmillWriteList", - "WindmillApplyList", - "WindmillFields", - "WindmillTextFields", - "WindmillGraphQL", -] - - -WindmillTextFields = Literal["external_id", "name", "windfarm"] -WindmillFields = Literal["external_id", "capacity", "name", "windfarm"] - -_WINDMILL_PROPERTIES_BY_FIELD = { - "external_id": "externalId", - "capacity": "capacity", - "name": "name", - "windfarm": "windfarm", -} - - -class WindmillGraphQL(GraphQLCore): - """This represents the reading version of windmill, used - when data is retrieved from CDF using GraphQL. - - It is used when retrieving data from CDF using GraphQL. - - Args: - space: The space where the node is located. - external_id: The external id of the windmill. - data_record: The data record of the windmill node. - blades: The blade field. - capacity: The capacity field. - metmast: The metmast field. - nacelle: The nacelle field. - name: The name field. - rotor: The rotor field. - windfarm: The windfarm field. - """ - - view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Windmill", "1") - blades: Optional[list[BladeGraphQL]] = Field(default=None, repr=False) - capacity: Optional[float] = None - metmast: Optional[list[MetmastGraphQL]] = Field(default=None, repr=False) - nacelle: Optional[NacelleGraphQL] = Field(default=None, repr=False) - name: Optional[str] = None - rotor: Optional[RotorGraphQL] = Field(default=None, repr=False) - windfarm: Optional[str] = None - - @model_validator(mode="before") - def parse_data_record(cls, values: Any) -> Any: - if not isinstance(values, dict): - return values - if "lastUpdatedTime" in values or "createdTime" in values: - values["dataRecord"] = DataRecordGraphQL( - created_time=values.pop("createdTime", None), - last_updated_time=values.pop("lastUpdatedTime", None), - ) - return values - - @field_validator("blades", "metmast", "nacelle", "rotor", mode="before") - def parse_graphql(cls, value: Any) -> Any: - if not isinstance(value, dict): - return value - if "items" in value: - return value["items"] - return value - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_read(self) -> Windmill: - """Convert this GraphQL format of windmill to the reading format.""" - if self.data_record is None: - raise ValueError("This object cannot be converted to a read format because it lacks a data record.") - return Windmill( - space=self.space, - external_id=self.external_id, - data_record=DataRecord( - version=0, - last_updated_time=self.data_record.last_updated_time, - created_time=self.data_record.created_time, - ), - blades=[blade.as_read() for blade in self.blades or []], - capacity=self.capacity, - metmast=[metmast.as_read() for metmast in self.metmast or []], - nacelle=self.nacelle.as_read() if isinstance(self.nacelle, GraphQLCore) else self.nacelle, - name=self.name, - rotor=self.rotor.as_read() if isinstance(self.rotor, GraphQLCore) else self.rotor, - windfarm=self.windfarm, - ) - - # We do the ignore argument type as we let pydantic handle the type checking - @no_type_check - def as_write(self) -> WindmillWrite: - """Convert this GraphQL format of windmill to the writing format.""" - return WindmillWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=0), - blades=[blade.as_write() for blade in self.blades or []], - capacity=self.capacity, - metmast=[metmast.as_write() for metmast in self.metmast or []], - nacelle=self.nacelle.as_write() if isinstance(self.nacelle, GraphQLCore) else self.nacelle, - name=self.name, - rotor=self.rotor.as_write() if isinstance(self.rotor, GraphQLCore) else self.rotor, - windfarm=self.windfarm, - ) - - -class Windmill(DomainModel): - """This represents the reading version of windmill. - - It is used to when data is retrieved from CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the windmill. - data_record: The data record of the windmill node. - blades: The blade field. - capacity: The capacity field. - metmast: The metmast field. - nacelle: The nacelle field. - name: The name field. - rotor: The rotor field. - windfarm: The windfarm field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Windmill", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, None] = None - blades: Optional[list[Union[Blade, str, dm.NodeId]]] = Field(default=None, repr=False) - capacity: Optional[float] = None - metmast: Optional[list[Union[Metmast, str, dm.NodeId]]] = Field(default=None, repr=False) - nacelle: Union[Nacelle, str, dm.NodeId, None] = Field(default=None, repr=False) - name: Optional[str] = None - rotor: Union[Rotor, str, dm.NodeId, None] = Field(default=None, repr=False) - windfarm: Optional[str] = None - - def as_write(self) -> WindmillWrite: - """Convert this read version of windmill to the writing version.""" - return WindmillWrite( - space=self.space, - external_id=self.external_id, - data_record=DataRecordWrite(existing_version=self.data_record.version), - blades=[blade.as_write() if isinstance(blade, DomainModel) else blade for blade in self.blades or []], - capacity=self.capacity, - metmast=[ - metmast.as_write() if isinstance(metmast, DomainModel) else metmast for metmast in self.metmast or [] - ], - nacelle=self.nacelle.as_write() if isinstance(self.nacelle, DomainModel) else self.nacelle, - name=self.name, - rotor=self.rotor.as_write() if isinstance(self.rotor, DomainModel) else self.rotor, - windfarm=self.windfarm, - ) - - def as_apply(self) -> WindmillWrite: - """Convert this read version of windmill to the writing version.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - @classmethod - def _update_connections( - cls, - instances: dict[dm.NodeId | str, Windmill], # type: ignore[override] - nodes_by_id: dict[dm.NodeId | str, DomainModel], - edges_by_source_node: dict[dm.NodeId, list[dm.Edge | DomainRelation]], - ) -> None: - from ._blade import Blade - from ._metmast import Metmast - from ._nacelle import Nacelle - from ._rotor import Rotor - - for instance in instances.values(): - if ( - isinstance(instance.nacelle, (dm.NodeId, str)) - and (nacelle := nodes_by_id.get(instance.nacelle)) - and isinstance(nacelle, Nacelle) - ): - instance.nacelle = nacelle - if ( - isinstance(instance.rotor, (dm.NodeId, str)) - and (rotor := nodes_by_id.get(instance.rotor)) - and isinstance(rotor, Rotor) - ): - instance.rotor = rotor - if edges := edges_by_source_node.get(instance.as_id()): - blades: list[Blade | str | dm.NodeId] = [] - metmast: list[Metmast | str | dm.NodeId] = [] - for edge in edges: - value: DomainModel | DomainRelation | str | dm.NodeId - if isinstance(edge, DomainRelation): - value = edge - else: - other_end: dm.DirectRelationReference = ( - edge.end_node - if edge.start_node.space == instance.space - and edge.start_node.external_id == instance.external_id - else edge.start_node - ) - destination: dm.NodeId | str = ( - as_node_id(other_end) - if other_end.space != DEFAULT_INSTANCE_SPACE - else other_end.external_id - ) - if destination in nodes_by_id: - value = nodes_by_id[destination] - else: - value = destination - edge_type = edge.edge_type if isinstance(edge, DomainRelation) else edge.type - - if edge_type == dm.DirectRelationReference("power-models", "Windmill.blades") and isinstance( - value, (Blade, str, dm.NodeId) - ): - blades.append(value) - if edge_type == dm.DirectRelationReference("power-models", "Windmill.metmast") and isinstance( - value, (Metmast, str, dm.NodeId) - ): - metmast.append(value) - - instance.blades = blades or None - instance.metmast = metmast or None - - -class WindmillWrite(DomainModelWrite): - """This represents the writing version of windmill. - - It is used to when data is sent to CDF. - - Args: - space: The space where the node is located. - external_id: The external id of the windmill. - data_record: The data record of the windmill node. - blades: The blade field. - capacity: The capacity field. - metmast: The metmast field. - nacelle: The nacelle field. - name: The name field. - rotor: The rotor field. - windfarm: The windfarm field. - """ - - _view_id: ClassVar[dm.ViewId] = dm.ViewId("power-models", "Windmill", "1") - - space: str = DEFAULT_INSTANCE_SPACE - node_type: Union[dm.DirectRelationReference, dm.NodeId, tuple[str, str], None] = None - blades: Optional[list[Union[BladeWrite, str, dm.NodeId]]] = Field(default=None, repr=False) - capacity: Optional[float] = None - metmast: Optional[list[Union[MetmastWrite, str, dm.NodeId]]] = Field(default=None, repr=False) - nacelle: Union[NacelleWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - name: Optional[str] = None - rotor: Union[RotorWrite, str, dm.NodeId, None] = Field(default=None, repr=False) - windfarm: Optional[str] = None - - @field_validator("blades", "metmast", "nacelle", "rotor", mode="before") - def as_node_id(cls, value: Any) -> Any: - if isinstance(value, dm.DirectRelationReference): - return dm.NodeId(value.space, value.external_id) - elif isinstance(value, tuple) and len(value) == 2 and all(isinstance(item, str) for item in value): - return dm.NodeId(value[0], value[1]) - elif isinstance(value, list): - return [cls.as_node_id(item) for item in value] - return value - - def _to_instances_write( - self, - cache: set[tuple[str, str]], - write_none: bool = False, - allow_version_increase: bool = False, - ) -> ResourcesWrite: - resources = ResourcesWrite() - if self.as_tuple_id() in cache: - return resources - - properties: dict[str, Any] = {} - - if self.capacity is not None or write_none: - properties["capacity"] = self.capacity - - if self.nacelle is not None: - properties["nacelle"] = { - "space": self.space if isinstance(self.nacelle, str) else self.nacelle.space, - "externalId": self.nacelle if isinstance(self.nacelle, str) else self.nacelle.external_id, - } - - if self.name is not None or write_none: - properties["name"] = self.name - - if self.rotor is not None: - properties["rotor"] = { - "space": self.space if isinstance(self.rotor, str) else self.rotor.space, - "externalId": self.rotor if isinstance(self.rotor, str) else self.rotor.external_id, - } - - if self.windfarm is not None or write_none: - properties["windfarm"] = self.windfarm - - if properties: - this_node = dm.NodeApply( - space=self.space, - external_id=self.external_id, - existing_version=None if allow_version_increase else self.data_record.existing_version, - type=as_direct_relation_reference(self.node_type), - sources=[ - dm.NodeOrEdgeData( - source=self._view_id, - properties=properties, - ) - ], - ) - resources.nodes.append(this_node) - cache.add(self.as_tuple_id()) - - edge_type = dm.DirectRelationReference("power-models", "Windmill.blades") - for blade in self.blades or []: - other_resources = DomainRelationWrite.from_edge_to_resources( - cache, - start_node=self, - end_node=blade, - edge_type=edge_type, - write_none=write_none, - allow_version_increase=allow_version_increase, - ) - resources.extend(other_resources) - - edge_type = dm.DirectRelationReference("power-models", "Windmill.metmast") - for metmast in self.metmast or []: - other_resources = DomainRelationWrite.from_edge_to_resources( - cache, - start_node=self, - end_node=metmast, - edge_type=edge_type, - write_none=write_none, - allow_version_increase=allow_version_increase, - ) - resources.extend(other_resources) - - if isinstance(self.nacelle, DomainModelWrite): - other_resources = self.nacelle._to_instances_write(cache) - resources.extend(other_resources) - - if isinstance(self.rotor, DomainModelWrite): - other_resources = self.rotor._to_instances_write(cache) - resources.extend(other_resources) - - return resources - - -class WindmillApply(WindmillWrite): - def __new__(cls, *args, **kwargs) -> WindmillApply: - warnings.warn( - "WindmillApply is deprecated and will be removed in v1.0. Use WindmillWrite instead." - "The motivation for this change is that Write is a more descriptive name for the writing version of the" - "Windmill.", - UserWarning, - stacklevel=2, - ) - return super().__new__(cls) - - -class WindmillList(DomainModelList[Windmill]): - """List of windmills in the read version.""" - - _INSTANCE = Windmill - - def as_write(self) -> WindmillWriteList: - """Convert these read versions of windmill to the writing versions.""" - return WindmillWriteList([node.as_write() for node in self.data]) - - def as_apply(self) -> WindmillWriteList: - """Convert these read versions of primitive nullable to the writing versions.""" - warnings.warn( - "as_apply is deprecated and will be removed in v1.0. Use as_write instead.", - UserWarning, - stacklevel=2, - ) - return self.as_write() - - @property - def blades(self) -> BladeList: - from ._blade import Blade, BladeList - - return BladeList([item for items in self.data for item in items.blades or [] if isinstance(item, Blade)]) - - @property - def metmast(self) -> MetmastList: - from ._metmast import Metmast, MetmastList - - return MetmastList([item for items in self.data for item in items.metmast or [] if isinstance(item, Metmast)]) - - @property - def nacelle(self) -> NacelleList: - from ._nacelle import Nacelle, NacelleList - - return NacelleList([item.nacelle for item in self.data if isinstance(item.nacelle, Nacelle)]) - - @property - def rotor(self) -> RotorList: - from ._rotor import Rotor, RotorList - - return RotorList([item.rotor for item in self.data if isinstance(item.rotor, Rotor)]) - - -class WindmillWriteList(DomainModelWriteList[WindmillWrite]): - """List of windmills in the writing version.""" - - _INSTANCE = WindmillWrite - - @property - def blades(self) -> BladeWriteList: - from ._blade import BladeWrite, BladeWriteList - - return BladeWriteList( - [item for items in self.data for item in items.blades or [] if isinstance(item, BladeWrite)] - ) - - @property - def metmast(self) -> MetmastWriteList: - from ._metmast import MetmastWrite, MetmastWriteList - - return MetmastWriteList( - [item for items in self.data for item in items.metmast or [] if isinstance(item, MetmastWrite)] - ) - - @property - def nacelle(self) -> NacelleWriteList: - from ._nacelle import NacelleWrite, NacelleWriteList - - return NacelleWriteList([item.nacelle for item in self.data if isinstance(item.nacelle, NacelleWrite)]) - - @property - def rotor(self) -> RotorWriteList: - from ._rotor import RotorWrite, RotorWriteList - - return RotorWriteList([item.rotor for item in self.data if isinstance(item.rotor, RotorWrite)]) - - -class WindmillApplyList(WindmillWriteList): ... - - -def _create_windmill_filter( - view_id: dm.ViewId, - min_capacity: float | None = None, - max_capacity: float | None = None, - nacelle: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - name: str | list[str] | None = None, - name_prefix: str | None = None, - rotor: ( - str - | tuple[str, str] - | dm.NodeId - | dm.DirectRelationReference - | Sequence[str | tuple[str, str] | dm.NodeId | dm.DirectRelationReference] - | None - ) = None, - windfarm: str | list[str] | None = None, - windfarm_prefix: str | None = None, - external_id_prefix: str | None = None, - space: str | list[str] | None = None, - filter: dm.Filter | None = None, -) -> dm.Filter | None: - filters: list[dm.Filter] = [] - if min_capacity is not None or max_capacity is not None: - filters.append(dm.filters.Range(view_id.as_property_ref("capacity"), gte=min_capacity, lte=max_capacity)) - if isinstance(nacelle, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(nacelle): - filters.append(dm.filters.Equals(view_id.as_property_ref("nacelle"), value=as_instance_dict_id(nacelle))) - if nacelle and isinstance(nacelle, Sequence) and not isinstance(nacelle, str) and not is_tuple_id(nacelle): - filters.append( - dm.filters.In(view_id.as_property_ref("nacelle"), values=[as_instance_dict_id(item) for item in nacelle]) - ) - if isinstance(name, str): - filters.append(dm.filters.Equals(view_id.as_property_ref("name"), value=name)) - if name and isinstance(name, list): - filters.append(dm.filters.In(view_id.as_property_ref("name"), values=name)) - if name_prefix is not None: - filters.append(dm.filters.Prefix(view_id.as_property_ref("name"), value=name_prefix)) - if isinstance(rotor, str | dm.NodeId | dm.DirectRelationReference) or is_tuple_id(rotor): - filters.append(dm.filters.Equals(view_id.as_property_ref("rotor"), value=as_instance_dict_id(rotor))) - if rotor and isinstance(rotor, Sequence) and not isinstance(rotor, str) and not is_tuple_id(rotor): - filters.append( - dm.filters.In(view_id.as_property_ref("rotor"), values=[as_instance_dict_id(item) for item in rotor]) - ) - if isinstance(windfarm, str): - filters.append(dm.filters.Equals(view_id.as_property_ref("windfarm"), value=windfarm)) - if windfarm and isinstance(windfarm, list): - filters.append(dm.filters.In(view_id.as_property_ref("windfarm"), values=windfarm)) - if windfarm_prefix is not None: - filters.append(dm.filters.Prefix(view_id.as_property_ref("windfarm"), value=windfarm_prefix)) - if external_id_prefix is not None: - filters.append(dm.filters.Prefix(["node", "externalId"], value=external_id_prefix)) - if isinstance(space, str): - filters.append(dm.filters.Equals(["node", "space"], value=space)) - if space and isinstance(space, list): - filters.append(dm.filters.In(["node", "space"], values=space)) - if filter: - filters.append(filter) - return dm.filters.And(*filters) if filters else None - - -class _WindmillQuery(NodeQueryCore[T_DomainModelList, WindmillList]): - _view_id = Windmill._view_id - _result_cls = Windmill - _result_list_cls_end = WindmillList - - def __init__( - self, - created_types: set[type], - creation_path: list[QueryCore], - client: CogniteClient, - result_list_cls: type[T_DomainModelList], - expression: dm.query.ResultSetExpression | None = None, - connection_name: str | None = None, - connection_type: Literal["reverse-list"] | None = None, - reverse_expression: dm.query.ResultSetExpression | None = None, - ): - from ._blade import _BladeQuery - from ._metmast import _MetmastQuery - from ._nacelle import _NacelleQuery - from ._rotor import _RotorQuery - - super().__init__( - created_types, - creation_path, - client, - result_list_cls, - expression, - dm.filters.HasData(views=[self._view_id]), - connection_name, - connection_type, - reverse_expression, - ) - - if _BladeQuery not in created_types: - self.blades = _BladeQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.EdgeResultSetExpression( - direction="outwards", - chain_to="destination", - ), - connection_name="blades", - ) - - if _MetmastQuery not in created_types: - self.metmast = _MetmastQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.EdgeResultSetExpression( - direction="outwards", - chain_to="destination", - ), - connection_name="metmast", - ) - - if _NacelleQuery not in created_types: - self.nacelle = _NacelleQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("nacelle"), - direction="outwards", - ), - connection_name="nacelle", - ) - - if _RotorQuery not in created_types: - self.rotor = _RotorQuery( - created_types.copy(), - self._creation_path, - client, - result_list_cls, - dm.query.NodeResultSetExpression( - through=self._view_id.as_property_ref("rotor"), - direction="outwards", - ), - connection_name="rotor", - ) - - self.space = StringFilter(self, ["node", "space"]) - self.external_id = StringFilter(self, ["node", "externalId"]) - self.capacity = FloatFilter(self, self._view_id.as_property_ref("capacity")) - self.name = StringFilter(self, self._view_id.as_property_ref("name")) - self.windfarm = StringFilter(self, self._view_id.as_property_ref("windfarm")) - self._filter_classes.extend( - [ - self.space, - self.external_id, - self.capacity, - self.name, - self.windfarm, - ] - ) - - def list_windmill(self, limit: int = DEFAULT_QUERY_LIMIT) -> WindmillList: - return self._list(limit=limit) - - -class WindmillQuery(_WindmillQuery[WindmillList]): - def __init__(self, client: CogniteClient): - super().__init__(set(), [], client, WindmillList) diff --git a/tests/data/models/Windmill/model.yaml b/tests/data/models/Windmill/model.yaml deleted file mode 100644 index be819c1a7..000000000 --- a/tests/data/models/Windmill/model.yaml +++ /dev/null @@ -1,916 +0,0 @@ -space: power-models -externalId: Windmill -name: Windmill -description: '' -version: '1' -views: -- space: power-models - externalId: Blade - name: Blade - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - is_damaged: - container: - space: power-models - externalId: Blade - containerPropertyIdentifier: is_damaged - type: - list: false - type: boolean - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: is_damaged - description: null - name: - container: - space: power-models - externalId: Blade - containerPropertyIdentifier: name - type: - list: false - collation: ucs_basic - type: text - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: name - description: null - sensor_positions: - type: - space: power-models - externalId: Blade.sensor_positions - source: - space: power-models - externalId: SensorPosition - version: '1' - type: view - name: sensor_positions - description: null - edgeSource: null - direction: outwards - connectionType: multi_edge_connection - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: Gearbox - name: Gearbox - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - displacement_x: - container: - space: power-models - externalId: Gearbox - containerPropertyIdentifier: displacement_x - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: displacement_x - description: null - displacement_y: - container: - space: power-models - externalId: Gearbox - containerPropertyIdentifier: displacement_y - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: displacement_y - description: null - displacement_z: - container: - space: power-models - externalId: Gearbox - containerPropertyIdentifier: displacement_z - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: displacement_z - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: Generator - name: Generator - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - generator_speed_controller: - container: - space: power-models - externalId: Generator - containerPropertyIdentifier: generator_speed_controller - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: generator_speed_controller - description: null - generator_speed_controller_reference: - container: - space: power-models - externalId: Generator - containerPropertyIdentifier: generator_speed_controller_reference - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: generator_speed_controller_reference - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: HighSpeedShaft - name: HighSpeedShaft - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - bending_moment_y: - container: - space: power-models - externalId: HighSpeedShaft - containerPropertyIdentifier: bending_moment_y - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: bending_moment_y - description: null - bending_monent_x: - container: - space: power-models - externalId: HighSpeedShaft - containerPropertyIdentifier: bending_monent_x - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: bending_monent_x - description: null - torque: - container: - space: power-models - externalId: HighSpeedShaft - containerPropertyIdentifier: torque - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: torque - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: MainShaft - name: MainShaft - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - bending_x: - container: - space: power-models - externalId: MainShaft - containerPropertyIdentifier: bending_x - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: bending_x - description: null - bending_y: - container: - space: power-models - externalId: MainShaft - containerPropertyIdentifier: bending_y - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: bending_y - description: null - calculated_tilt_moment: - container: - space: power-models - externalId: MainShaft - containerPropertyIdentifier: calculated_tilt_moment - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: calculated_tilt_moment - description: null - calculated_yaw_moment: - container: - space: power-models - externalId: MainShaft - containerPropertyIdentifier: calculated_yaw_moment - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: calculated_yaw_moment - description: null - torque: - container: - space: power-models - externalId: MainShaft - containerPropertyIdentifier: torque - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: torque - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: Metmast - name: Metmast - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - position: - container: - space: power-models - externalId: Metmast - containerPropertyIdentifier: position - type: - list: false - type: float64 - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: position - description: null - temperature: - container: - space: power-models - externalId: Metmast - containerPropertyIdentifier: temperature - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: temperature - description: null - tilt_angle: - container: - space: power-models - externalId: Metmast - containerPropertyIdentifier: tilt_angle - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: tilt_angle - description: null - wind_speed: - container: - space: power-models - externalId: Metmast - containerPropertyIdentifier: wind_speed - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: wind_speed - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: Nacelle - name: Nacelle - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - acc_from_back_side_x: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: acc_from_back_side_x - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: acc_from_back_side_x - description: null - acc_from_back_side_y: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: acc_from_back_side_y - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: acc_from_back_side_y - description: null - acc_from_back_side_z: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: acc_from_back_side_z - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: acc_from_back_side_z - description: null - gearbox: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: gearbox - type: - list: false - type: direct - source: - space: power-models - externalId: Gearbox - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: gearbox - description: null - generator: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: generator - type: - list: false - type: direct - source: - space: power-models - externalId: Generator - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: generator - description: null - high_speed_shaft: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: high_speed_shaft - type: - list: false - type: direct - source: - space: power-models - externalId: HighSpeedShaft - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: high_speed_shaft - description: null - main_shaft: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: main_shaft - type: - list: false - type: direct - source: - space: power-models - externalId: MainShaft - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: main_shaft - description: null - power_inverter: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: power_inverter - type: - list: false - type: direct - source: - space: power-models - externalId: PowerInverter - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: power_inverter - description: null - yaw_direction: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: yaw_direction - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: yaw_direction - description: null - yaw_error: - container: - space: power-models - externalId: Nacelle - containerPropertyIdentifier: yaw_error - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: yaw_error - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: PowerInverter - name: PowerInverter - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - active_power_total: - container: - space: power-models - externalId: PowerInverter - containerPropertyIdentifier: active_power_total - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: active_power_total - description: null - apparent_power_total: - container: - space: power-models - externalId: PowerInverter - containerPropertyIdentifier: apparent_power_total - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: apparent_power_total - description: null - reactive_power_total: - container: - space: power-models - externalId: PowerInverter - containerPropertyIdentifier: reactive_power_total - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: reactive_power_total - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: Rotor - name: Rotor - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - rotor_speed_controller: - container: - space: power-models - externalId: Rotor - containerPropertyIdentifier: rotor_speed_controller - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: rotor_speed_controller - description: null - rpm_low_speed_shaft: - container: - space: power-models - externalId: Rotor - containerPropertyIdentifier: rpm_low_speed_shaft - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: rpm_low_speed_shaft - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: SensorPosition - name: SensorPosition - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - edgewise_bend_mom_crosstalk_corrected: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: edgewise_bend_mom_crosstalk_corrected - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: edgewise_bend_mom_crosstalk_corrected - description: null - edgewise_bend_mom_offset: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: edgewise_bend_mom_offset - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: edgewise_bend_mom_offset - description: null - edgewise_bend_mom_offset_crosstalk_corrected: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: edgewise_bend_mom_offset_crosstalk_corrected - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: edgewise_bend_mom_offset_crosstalk_corrected - description: null - edgewisewise_bend_mom: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: edgewisewise_bend_mom - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: edgewisewise_bend_mom - description: null - flapwise_bend_mom: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: flapwise_bend_mom - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: flapwise_bend_mom - description: null - flapwise_bend_mom_crosstalk_corrected: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: flapwise_bend_mom_crosstalk_corrected - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: flapwise_bend_mom_crosstalk_corrected - description: null - flapwise_bend_mom_offset: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: flapwise_bend_mom_offset - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: flapwise_bend_mom_offset - description: null - flapwise_bend_mom_offset_crosstalk_corrected: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: flapwise_bend_mom_offset_crosstalk_corrected - type: - list: false - type: timeseries - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: flapwise_bend_mom_offset_crosstalk_corrected - description: null - position: - container: - space: power-models - externalId: SensorPosition - containerPropertyIdentifier: position - type: - list: false - type: float64 - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: position - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -- space: power-models - externalId: Windmill - name: Windmill - implements: [] - version: '1' - writable: true - usedFor: node - isGlobal: false - properties: - blades: - type: - space: power-models - externalId: Windmill.blades - source: - space: power-models - externalId: Blade - version: '1' - type: view - name: blades - description: null - edgeSource: null - direction: outwards - connectionType: multi_edge_connection - capacity: - container: - space: power-models - externalId: Windmill - containerPropertyIdentifier: capacity - type: - list: false - type: float64 - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: capacity - description: null - metmast: - type: - space: power-models - externalId: Windmill.metmast - source: - space: power-models - externalId: Metmast - version: '1' - type: view - name: metmast - description: null - edgeSource: null - direction: outwards - connectionType: multi_edge_connection - nacelle: - container: - space: power-models - externalId: Windmill - containerPropertyIdentifier: nacelle - type: - list: false - type: direct - source: - space: power-models - externalId: Nacelle - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: nacelle - description: null - name: - container: - space: power-models - externalId: Windmill - containerPropertyIdentifier: name - type: - list: false - collation: ucs_basic - type: text - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: name - description: null - rotor: - container: - space: power-models - externalId: Windmill - containerPropertyIdentifier: rotor - type: - list: false - type: direct - source: - space: power-models - externalId: Rotor - version: '1' - nullable: true - immutable: false - autoIncrement: false - defaultValue: null - name: rotor - description: null - windfarm: - container: - space: power-models - externalId: Windmill - containerPropertyIdentifier: windfarm - type: - list: false - collation: ucs_basic - type: text - nullable: true - immutable: false - autoIncrement: false - source: null - defaultValue: null - name: windfarm - description: null - lastUpdatedTime: 1703508218266 - createdTime: 1703508218266 -isGlobal: false -lastUpdatedTime: 1703508242349 -createdTime: 1703508219198