From c69ab494150fe363011bb55a6440aa3eb1d378f8 Mon Sep 17 00:00:00 2001 From: Alex Luck Date: Fri, 10 Oct 2025 12:40:20 -0700 Subject: [PATCH 1/6] update sift client examples --- python/docs/examples/basic.ipynb | 950 ++++++++++++++++++ python/docs/overrides/main.html | 10 + python/examples/sift_client/assets/main.py | 27 - python/examples/sift_client/ping/main.py | 27 - python/lib/sift_client/sift_types/__init__.py | 131 +++ python/mkdocs.yml | 5 +- 6 files changed, 1095 insertions(+), 55 deletions(-) create mode 100644 python/docs/examples/basic.ipynb delete mode 100644 python/examples/sift_client/assets/main.py delete mode 100644 python/examples/sift_client/ping/main.py diff --git a/python/docs/examples/basic.ipynb b/python/docs/examples/basic.ipynb new file mode 100644 index 000000000..2a3e9de8e --- /dev/null +++ b/python/docs/examples/basic.ipynb @@ -0,0 +1,950 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "header", + "metadata": {}, + "source": [ + "# Sift Client Basic Example\n", + "\n", + "This notebook demonstrates the core features of the Sift Python client:\n", + "- Initializing the Sift client\n", + "- Finding assets\n", + "- Finding runs\n", + "- Searching channels\n", + "- Pulling data\n", + "- Creating calculated channels\n", + "- Setting rules" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Running this notebook\n", + "\n", + "This notebook is written in Jupyter Notebook format and can be run in any Jupyter environment.\n", + "\n", + "Some additional package prerequisites are required to run this notebook:\n", + "- `notebook` for running Jupyter Notebooks\n", + "- `python-dotenv` for loading environment variables\n", + "- `rich` for pretty-printing output\n", + "- `pandas` for data manipulation and analysis\n", + "- `matplotlib` for data visualization\n", + "\n", + "You can install these packages using `pip install notebook rich python-dotenv pandas matplotlib`." + ], + "id": "ef259d05fa338580" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Setup and Initialization\n", + "\n", + "First, import the necessary modules and initialize the Sift client with your credentials.\n", + "\n", + "Best practice is to access credentials using environment variables or a `.env` file with `python-dotenv`. Avoid hardcoding your API in any code you write." + ], + "id": "f2bbc03e85aa2973" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:41:13.634541Z", + "start_time": "2025-10-10T18:41:13.031402Z" + } + }, + "cell_type": "code", + "source": [ + "import os\n", + "from datetime import datetime, timedelta\n", + "from rich import print\n", + "from dotenv import load_dotenv\n", + "from sift_client import SiftClient\n", + "from sift_client.sift_types import (\n", + " ChannelReference,\n", + " CalculatedChannelCreate,\n", + " RuleCreate,\n", + " RuleAction,\n", + " RuleAnnotationType,\n", + ")" + ], + "id": "497279d83878122e", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/alexluck/Projects/sift-clients/python/lib/sift_client/resources/_base.py:9: SiftExperimentalWarning: `sift_client` is experimental and is subject to change. Use with caution.\n", + " _sift_client_experimental_warning()\n" + ] + } + ], + "execution_count": 1 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:41:13.671729Z", + "start_time": "2025-10-10T18:41:13.639382Z" + } + }, + "cell_type": "code", + "source": [ + "# Get our environment variables\n", + "load_dotenv() # Load environment variables from .env file\n", + "api_key = os.getenv(\"SIFT_API_KEY\")\n", + "grpc_url = os.getenv(\"SIFT_GRPC_URI\")\n", + "rest_url = os.getenv(\"SIFT_REST_URI\")\n", + "\n", + "client = SiftClient(\n", + " api_key=api_key,\n", + " grpc_url=grpc_url,\n", + " rest_url=rest_url\n", + ")\n", + "\n", + "print(\"✓ Sift client initialized successfully\")" + ], + "id": "3492e85e32f1f568", + "outputs": [ + { + "data": { + "text/plain": [ + "✓ Sift client initialized successfully\n" + ], + "text/html": [ + "
✓ Sift client initialized successfully\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 2 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Sift Resources\n", + "\n", + "Sift objects, such as Assets, Runs, etc. are all accessed via their API resources.\n", + "\n", + "The [SiftClient](../../reference/sift_client/#sift_client.SiftClient) class provides these resources as properties:\n", + "- `assets`\n", + "- `runs`\n", + "- etc.\n", + "\n", + "Asynchronous versions are also available by accessing the `async_` property of the client. For example:\n", + "- `client.async_.assets`\n", + "- `client.async_.runs`\n", + "- etc.\n", + "\n", + "For example, the `Ping` resource can be used for a basic health check:" + ], + "id": "378db56e29b1a355" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:41:16.613462Z", + "start_time": "2025-10-10T18:41:14.801033Z" + } + }, + "cell_type": "code", + "source": "client.ping.ping()", + "id": "fb2db56e076eabec", + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello from Sift!'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 3 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Assets and Runs\n", + "\n", + "Assets represent physical or logical entities in your system (e.g., vehicles, machines, devices). Runs represent time-bounded operational periods for an asset (e.g., a flight, a test, a mission)." + ], + "id": "25d1ee945819d7ec" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Resources generally offer similar interaction patterns and methods. For example, the `AssetsAPI` has:\n", + "- `get`\n", + "- `list_`\n", + "- `find`\n", + "- `update`\n", + "- `archive`\n", + "- `unarchive`\n", + "\n", + "Other resources may offer additional methods such as `create`." + ], + "id": "894e74a9efdc603e" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Listing, Finding, and Getting\n", + "\n", + "`list_` can be used to retrieve objects that match a specific set of criteria:" + ], + "id": "86b7b129ccbb2956" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:50:58.703512Z", + "start_time": "2025-10-10T18:50:58.635145Z" + } + }, + "cell_type": "code", + "source": [ + "# List all assets (limited to 10 for this example)\n", + "assets = client.assets.list_(name_contains=\"Mars\", limit=5)\n", + "for asset in assets:\n", + " print(f\"Name: {asset.name}, ID: {asset.id_}\")\n" + ], + "id": "49992189f605c3e4", + "outputs": [ + { + "data": { + "text/plain": [ + "Name: MarsRoverIngestPusher, ID: \u001B[93m429b864b-0911-4e23-b9d1-2a1fba4d441c\u001B[0m\n" + ], + "text/html": [ + "
Name: MarsRoverIngestPusher, ID: 429b864b-0911-4e23-b9d1-2a1fba4d441c\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "Name: Mars Rover \u001B[1m[\u001B[0mJonno export test\u001B[1m]\u001B[0m, ID: \u001B[93m5d86ed46-dec6-41c8-8680-a0ba02d9e546\u001B[0m\n" + ], + "text/html": [ + "
Name: Mars Rover [Jonno export test], ID: 5d86ed46-dec6-41c8-8680-a0ba02d9e546\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "Name: MarsRover_pb4, ID: \u001B[93m9bb3bfec-840d-40b7-a5ab-25591f9a1b38\u001B[0m\n" + ], + "text/html": [ + "
Name: MarsRover_pb4, ID: 9bb3bfec-840d-40b7-a5ab-25591f9a1b38\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "Name: MarsRover, ID: \u001B[93m611914d3-ffb1-402e-ae1e-5eb3e66dea7c\u001B[0m\n" + ], + "text/html": [ + "
Name: MarsRover, ID: 611914d3-ffb1-402e-ae1e-5eb3e66dea7c\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "Name: MarsRover42NaN, ID: \u001B[93m0ad88099-1aea-461c-91b5-0a91c7811f74\u001B[0m\n" + ], + "text/html": [ + "
Name: MarsRover42NaN, ID: 0ad88099-1aea-461c-91b5-0a91c7811f74\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 16 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "`find` can be used to find a single matching object. It will return an error if multiple are found. It takes the same arguments and filters as `list_`.", + "id": "a04618d6724e3a2d" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:50:58.768704Z", + "start_time": "2025-10-10T18:50:58.712159Z" + } + }, + "cell_type": "code", + "source": [ + "# Find a specific asset by name\n", + "asset_name = \"MarsRover0\"\n", + "asset = client.assets.find(name=asset_name)\n", + "print(asset)" + ], + "id": "8b4b9ce9b806a576", + "outputs": [ + { + "data": { + "text/plain": [ + "\u001B[1;35mAsset\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'MarsRover0'\u001B[0m,\n", + " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'simulator'\u001B[0m, \u001B[32m'speed-test'\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[32m'vehicle_type'\u001B[0m: \u001B[32m'rover'\u001B[0m, \u001B[32m'vehicle_version'\u001B[0m: \u001B[1;36m123123123.0\u001B[0m, \u001B[32m'version_active'\u001B[0m: \u001B[3;92mTrue\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m1970\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Asset(\n",
+       "    id_='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    name='MarsRover0',\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    tags=['simulator', 'speed-test'],\n",
+       "    metadata={'vehicle_type': 'rover', 'vehicle_version': 123123123.0, 'version_active': True},\n",
+       "    is_archived=False,\n",
+       "    archived_date=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 17 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "When we know exactly what we are looking for, we can use `get`.", + "id": "1df0e447f3a04c98" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:50:58.831165Z", + "start_time": "2025-10-10T18:50:58.773015Z" + } + }, + "cell_type": "code", + "source": [ + "# Get the exact asset by ID\n", + "asset = client.assets.get(asset_id=asset.id_)\n", + "print(asset)" + ], + "id": "d8c650d021ff4af8", + "outputs": [ + { + "data": { + "text/plain": [ + "\u001B[1;35mAsset\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'MarsRover0'\u001B[0m,\n", + " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'simulator'\u001B[0m, \u001B[32m'speed-test'\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[32m'vehicle_type'\u001B[0m: \u001B[32m'rover'\u001B[0m, \u001B[32m'vehicle_version'\u001B[0m: \u001B[1;36m123123123.0\u001B[0m, \u001B[32m'version_active'\u001B[0m: \u001B[3;92mTrue\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m1970\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Asset(\n",
+       "    id_='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    name='MarsRover0',\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    tags=['simulator', 'speed-test'],\n",
+       "    metadata={'vehicle_type': 'rover', 'vehicle_version': 123123123.0, 'version_active': True},\n",
+       "    is_archived=False,\n",
+       "    archived_date=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 18 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Creating, Updating, and Archiving\n", + "\n", + "Most resources offer `create`, `update`, and `archive` methods. " + ], + "id": "e8ebf9754df8f646" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T18:51:57.257730Z", + "start_time": "2025-10-10T18:51:57.142330Z" + } + }, + "cell_type": "code", + "source": [ + "# List runs for the selected asset\n", + "runs = client.runs.list_(\n", + " assets=[asset.id_],\n", + " limit=10,\n", + " order_by=\"start_time desc\"\n", + ")\n", + "\n", + "print(f\"Found {len(runs)} runs for asset '{asset.name}':\")\n", + "for run in runs:\n", + " status = \"Running\" if run.stop_time is None else \"Stopped\"\n", + " print(f\" - {run.name} ({status})\")\n", + " print(f\" Start: {run.start_time}\")\n", + " if run.stop_time:\n", + " print(f\" Stop: {run.stop_time}\")" + ], + "id": "58645b9030c86cc4", + "outputs": [ + { + "ename": "AioRpcError", + "evalue": ":1:25: undeclared reference to 'asset_ids' (in container '')\n | is_archived == false && asset_ids in ['61d6e4f0-8287-4678-b071-18a95fcd9db6']\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"\n\tdebug_error_string = \"UNKNOWN:Error received from peer {created_time:\"2025-10-10T11:51:57.213813-07:00\", grpc_status:3, grpc_message:\"invalid argument: failed to compile filter: ERROR: :1:25: undeclared reference to \\'asset_ids\\' (in container \\'\\')\\n | is_archived == false && asset_ids in [\\'61d6e4f0-8287-4678-b071-18a95fcd9db6\\']\\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"}\"\n>", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mAioRpcError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[20], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m# List runs for the selected asset\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m runs \u001B[38;5;241m=\u001B[39m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mruns\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mlist_\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 3\u001B[0m \u001B[43m \u001B[49m\u001B[43massets\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43masset\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mid_\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 4\u001B[0m \u001B[43m \u001B[49m\u001B[43mlimit\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m10\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 5\u001B[0m \u001B[43m \u001B[49m\u001B[43morder_by\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mstart_time desc\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\n\u001B[1;32m 6\u001B[0m \u001B[43m)\u001B[49m\n\u001B[1;32m 8\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mFound \u001B[39m\u001B[38;5;132;01m{\u001B[39;00m\u001B[38;5;28mlen\u001B[39m(runs)\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m runs for asset \u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;132;01m{\u001B[39;00masset\u001B[38;5;241m.\u001B[39mname\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m:\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m 9\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m run \u001B[38;5;129;01min\u001B[39;00m runs:\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:72\u001B[0m, in \u001B[0;36mgenerate_sync_api.._make_sync..sync_func\u001B[0;34m(self, *a, **kw)\u001B[0m\n\u001B[1;32m 70\u001B[0m \u001B[38;5;129m@wraps\u001B[39m(async_func)\n\u001B[1;32m 71\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21msync_func\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39ma, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkw):\n\u001B[0;32m---> 72\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_run\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mgetattr\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_async_impl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfunc_name\u001B[49m\u001B[43m)\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43ma\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkw\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:56\u001B[0m, in \u001B[0;36mgenerate_sync_api.._run\u001B[0;34m(self, coro)\u001B[0m\n\u001B[1;32m 54\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_run\u001B[39m(\u001B[38;5;28mself\u001B[39m, coro):\n\u001B[1;32m 55\u001B[0m loop \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_async_impl\u001B[38;5;241m.\u001B[39mclient\u001B[38;5;241m.\u001B[39mget_asyncio_loop()\n\u001B[0;32m---> 56\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43masyncio\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrun_coroutine_threadsafe\u001B[49m\u001B[43m(\u001B[49m\u001B[43mcoro\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mloop\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mresult\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:444\u001B[0m, in \u001B[0;36mFuture.result\u001B[0;34m(self, timeout)\u001B[0m\n\u001B[1;32m 442\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m CancelledError()\n\u001B[1;32m 443\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_state \u001B[38;5;241m==\u001B[39m FINISHED:\n\u001B[0;32m--> 444\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__get_result\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 445\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 446\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTimeoutError\u001B[39;00m()\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:389\u001B[0m, in \u001B[0;36mFuture.__get_result\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 387\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception:\n\u001B[1;32m 388\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 389\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception\n\u001B[1;32m 390\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n\u001B[1;32m 391\u001B[0m \u001B[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001B[39;00m\n\u001B[1;32m 392\u001B[0m \u001B[38;5;28mself\u001B[39m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/resources/runs.py:171\u001B[0m, in \u001B[0;36mRunsAPIAsync.list_\u001B[0;34m(self, name, name_contains, name_regex, run_ids, client_keys, created_after, created_before, modified_after, modified_before, created_by, modified_by, metadata, assets, duration_less_than, duration_greater_than, start_time_after, start_time_before, stop_time_after, stop_time_before, is_stopped, description_contains, include_archived, filter_query, order_by, limit)\u001B[0m\n\u001B[1;32m 168\u001B[0m filter_parts\u001B[38;5;241m.\u001B[39mappend(cel\u001B[38;5;241m.\u001B[39mnot_(cel\u001B[38;5;241m.\u001B[39mequals_null(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstop_time\u001B[39m\u001B[38;5;124m\"\u001B[39m)))\n\u001B[1;32m 169\u001B[0m query_filter \u001B[38;5;241m=\u001B[39m cel\u001B[38;5;241m.\u001B[39mand_(\u001B[38;5;241m*\u001B[39mfilter_parts)\n\u001B[0;32m--> 171\u001B[0m runs \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_low_level_client\u001B[38;5;241m.\u001B[39mlist_all_runs(\n\u001B[1;32m 172\u001B[0m query_filter\u001B[38;5;241m=\u001B[39mquery_filter \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 173\u001B[0m order_by\u001B[38;5;241m=\u001B[39morder_by,\n\u001B[1;32m 174\u001B[0m max_results\u001B[38;5;241m=\u001B[39mlimit,\n\u001B[1;32m 175\u001B[0m )\n\u001B[1;32m 176\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_apply_client_to_instances(runs)\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/runs.py:114\u001B[0m, in \u001B[0;36mRunsLowLevelClient.list_all_runs\u001B[0;34m(self, query_filter, order_by, max_results)\u001B[0m\n\u001B[1;32m 97\u001B[0m \u001B[38;5;28;01masync\u001B[39;00m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mlist_all_runs\u001B[39m(\n\u001B[1;32m 98\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[1;32m 99\u001B[0m \u001B[38;5;241m*\u001B[39m,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 102\u001B[0m max_results: \u001B[38;5;28mint\u001B[39m \u001B[38;5;241m|\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 103\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mlist\u001B[39m[Run]:\n\u001B[1;32m 104\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"List all runs with optional filtering.\u001B[39;00m\n\u001B[1;32m 105\u001B[0m \n\u001B[1;32m 106\u001B[0m \u001B[38;5;124;03m Args:\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 112\u001B[0m \u001B[38;5;124;03m A list of all matching runs.\u001B[39;00m\n\u001B[1;32m 113\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[0;32m--> 114\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_handle_pagination(\n\u001B[1;32m 115\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mlist_runs,\n\u001B[1;32m 116\u001B[0m kwargs\u001B[38;5;241m=\u001B[39m{\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mquery_filter\u001B[39m\u001B[38;5;124m\"\u001B[39m: query_filter},\n\u001B[1;32m 117\u001B[0m order_by\u001B[38;5;241m=\u001B[39morder_by,\n\u001B[1;32m 118\u001B[0m max_results\u001B[38;5;241m=\u001B[39mmax_results,\n\u001B[1;32m 119\u001B[0m )\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/base.py:41\u001B[0m, in \u001B[0;36mLowLevelClientBase._handle_pagination\u001B[0;34m(func, kwargs, page_size, page_token, order_by, max_results)\u001B[0m\n\u001B[1;32m 39\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m max_results \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;28mlen\u001B[39m(results) \u001B[38;5;241m>\u001B[39m\u001B[38;5;241m=\u001B[39m max_results:\n\u001B[1;32m 40\u001B[0m \u001B[38;5;28;01mbreak\u001B[39;00m\n\u001B[0;32m---> 41\u001B[0m response, page_token \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m func(\n\u001B[1;32m 42\u001B[0m page_size\u001B[38;5;241m=\u001B[39mpage_size,\n\u001B[1;32m 43\u001B[0m page_token\u001B[38;5;241m=\u001B[39mpage_token,\n\u001B[1;32m 44\u001B[0m order_by\u001B[38;5;241m=\u001B[39morder_by,\n\u001B[1;32m 45\u001B[0m \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m 46\u001B[0m )\n\u001B[1;32m 47\u001B[0m results\u001B[38;5;241m.\u001B[39mextend(response)\n\u001B[1;32m 48\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m page_token \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/runs.py:91\u001B[0m, in \u001B[0;36mRunsLowLevelClient.list_runs\u001B[0;34m(self, page_size, page_token, query_filter, order_by)\u001B[0m\n\u001B[1;32m 88\u001B[0m request_kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124morder_by\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m order_by\n\u001B[1;32m 90\u001B[0m request \u001B[38;5;241m=\u001B[39m ListRunsRequest(\u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mrequest_kwargs)\n\u001B[0;32m---> 91\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grpc_client\u001B[38;5;241m.\u001B[39mget_stub(RunServiceStub)\u001B[38;5;241m.\u001B[39mListRuns(request)\n\u001B[1;32m 92\u001B[0m response \u001B[38;5;241m=\u001B[39m cast(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mListRunsResponse\u001B[39m\u001B[38;5;124m\"\u001B[39m, response)\n\u001B[1;32m 94\u001B[0m runs \u001B[38;5;241m=\u001B[39m [Run\u001B[38;5;241m.\u001B[39m_from_proto(run) \u001B[38;5;28;01mfor\u001B[39;00m run \u001B[38;5;129;01min\u001B[39;00m response\u001B[38;5;241m.\u001B[39mruns]\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_interceptor.py:472\u001B[0m, in \u001B[0;36m_InterceptedUnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 470\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__await__\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[1;32m 471\u001B[0m call \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_interceptors_task\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[0;32m--> 472\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m call\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[1;32m 473\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_call.py:327\u001B[0m, in \u001B[0;36m_UnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 325\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m asyncio\u001B[38;5;241m.\u001B[39mCancelledError()\n\u001B[1;32m 326\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 327\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m _create_rpc_error(\n\u001B[1;32m 328\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_initial_metadata,\n\u001B[1;32m 329\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_status,\n\u001B[1;32m 330\u001B[0m )\n\u001B[1;32m 331\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 332\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", + "\u001B[0;31mAioRpcError\u001B[0m: :1:25: undeclared reference to 'asset_ids' (in container '')\n | is_archived == false && asset_ids in ['61d6e4f0-8287-4678-b071-18a95fcd9db6']\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"\n\tdebug_error_string = \"UNKNOWN:Error received from peer {created_time:\"2025-10-10T11:51:57.213813-07:00\", grpc_status:3, grpc_message:\"invalid argument: failed to compile filter: ERROR: :1:25: undeclared reference to \\'asset_ids\\' (in container \\'\\')\\n | is_archived == false && asset_ids in [\\'61d6e4f0-8287-4678-b071-18a95fcd9db6\\']\\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"}\"\n>" + ] + } + ], + "execution_count": 20 + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Get a specific run\n", + "if runs:\n", + " run = runs[0]\n", + " print(f\"✓ Selected run: {run.name}\")\n", + " print(f\" ID: {run.id_}\")\n", + " print(f\" Start time: {run.start_time}\")\n", + " print(f\" Stop time: {run.stop_time or 'Still running'}\")\n", + "else:\n", + " print(\"No runs found for this asset\")\n", + " run = None" + ], + "id": "76b25f66938cf1b6" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Filter runs by time range\n", + "recent_runs = client.runs.list_(\n", + " assets=[asset.id_],\n", + " start_time_after=datetime.now() - timedelta(days=7),\n", + " limit=5\n", + ")\n", + "\n", + "print(f\"Runs started in the last 7 days: {len(recent_runs)}\")" + ], + "id": "15c0bca4bde0101b" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Searching Channels\n", + "\n", + "Channels represent time-series data streams (e.g., sensor readings, telemetry)." + ], + "id": "c1830f179b22cb43" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# List channels for the selected asset\n", + "channels = client.channels.list_(\n", + " asset=asset.id_,\n", + " limit=20\n", + ")\n", + "\n", + "print(f\"Found {len(channels)} channels for asset '{asset.name}':\")\n", + "for channel in channels[:10]: # Show first 10\n", + " print(f\" - {channel.name}\")\n", + " if channel.description:\n", + " print(f\" Description: {channel.description}\")\n", + " if channel.units:\n", + " print(f\" Units: {channel.units}\")" + ], + "id": "9c5a1b60c0fce9fc" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Search for specific channels by name pattern\n", + "# Replace with a pattern that matches your channel names\n", + "velocity_channels = client.channels.list_(\n", + " asset=asset.id_,\n", + " name_contains=\"velocity\",\n", + " limit=10\n", + ")\n", + "\n", + "print(f\"Channels containing 'velocity': {len(velocity_channels)}\")\n", + "for ch in velocity_channels:\n", + " print(f\" - {ch.name}\")" + ], + "id": "c2317d7f561926d6" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Get channels for a specific run\n", + "if run:\n", + " run_channels = client.channels.list_(\n", + " run=run.id_,\n", + " limit=10\n", + " )\n", + " print(f\"Channels in run '{run.name}': {len(run_channels)}\")\n", + " for ch in run_channels:\n", + " print(f\" - {ch.name}\")" + ], + "id": "1601a55853281e95" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Pulling Data\n", + "\n", + "Retrieve time-series data from channels as pandas DataFrames." + ], + "id": "7c611ee731605cbd" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Get data for specific channels\n", + "if channels and run:\n", + " # Select first 3 channels for this example\n", + " selected_channels = channels[:3]\n", + "\n", + " print(f\"Fetching data for {len(selected_channels)} channels...\")\n", + "\n", + " # Get data as a dictionary of pandas DataFrames\n", + " data = client.channels.get_data(\n", + " channels=selected_channels,\n", + " run=run.id_,\n", + " limit=1000 # Limit to 1000 data points per channel\n", + " )\n", + "\n", + " print(f\"\\n✓ Retrieved data for {len(data)} channels:\")\n", + " for channel_name, df in data.items():\n", + " print(f\"\\n Channel: {channel_name}\")\n", + " print(f\" Data points: {len(df)}\")\n", + " if len(df) > 0:\n", + " print(f\" Columns: {list(df.columns)}\")\n", + " print(f\" Sample data:\")\n", + " print(df.head())\n", + "else:\n", + " print(\"No channels or run available to fetch data\")" + ], + "id": "b6b40678b0bbe34e" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Get data for a specific time range\n", + "if channels and run and run.start_time:\n", + " selected_channels = channels[:2]\n", + "\n", + " # Get data for first hour of the run\n", + " start_time = run.start_time\n", + " end_time = start_time + timedelta(hours=1)\n", + "\n", + " print(f\"Fetching data from {start_time} to {end_time}...\")\n", + "\n", + " data = client.channels.get_data(\n", + " channels=selected_channels,\n", + " run=run.id_,\n", + " start_time=start_time,\n", + " end_time=end_time\n", + " )\n", + "\n", + " print(f\"\\n✓ Retrieved time-ranged data:\")\n", + " for channel_name, df in data.items():\n", + " print(f\" {channel_name}: {len(df)} data points\")" + ], + "id": "258bccc4cd8868e2" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Creating Calculated Channels\n", + "\n", + "Calculated channels allow you to create derived metrics from existing channels using mathematical expressions." + ], + "id": "b6c81e31a31fdc03" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Create a calculated channel\n", + "# This example creates a channel that divides two existing channels\n", + "# Replace channel names with actual channels from your system\n", + "\n", + "if len(channels) >= 2:\n", + " # Use first two channels for this example\n", + " channel1 = channels[0]\n", + " channel2 = channels[1]\n", + "\n", + " calc_channel_name = f\"{channel1.name}_per_{channel2.name}\"\n", + "\n", + " # Check if calculated channel already exists\n", + " existing = client.calculated_channels.find(\n", + " name=calc_channel_name,\n", + " asset=asset.id_\n", + " )\n", + "\n", + " if existing:\n", + " print(f\"Calculated channel '{calc_channel_name}' already exists\")\n", + " calc_channel = existing\n", + " else:\n", + " print(f\"Creating calculated channel: {calc_channel_name}\")\n", + "\n", + " calc_channel = client.calculated_channels.create(\n", + " CalculatedChannelCreate(\n", + " name=calc_channel_name,\n", + " description=f\"Ratio of {channel1.name} to {channel2.name}\",\n", + " expression=\"$1 / $2\", # $1 and $2 refer to the channel references below\n", + " channel_references=[\n", + " ChannelReference(\n", + " channel_reference=\"$1\",\n", + " channel_identifier=channel1.name\n", + " ),\n", + " ChannelReference(\n", + " channel_reference=\"$2\",\n", + " channel_identifier=channel2.name\n", + " ),\n", + " ],\n", + " units=f\"{channel1.units or 'unit1'}/{channel2.units or 'unit2'}\",\n", + " asset_ids=[asset.id_],\n", + " )\n", + " )\n", + "\n", + " print(f\"✓ Created calculated channel: {calc_channel.name}\")\n", + " print(f\" ID: {calc_channel.id_}\")\n", + " print(f\" Expression: {calc_channel.expression}\")\n", + "else:\n", + " print(\"Not enough channels available to create a calculated channel\")\n", + " calc_channel = None" + ], + "id": "70a5b0d39e5230c4" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# List all calculated channels for the asset\n", + "calc_channels = client.calculated_channels.list_(\n", + " asset=asset.id_,\n", + " limit=10\n", + ")\n", + "\n", + "print(f\"Calculated channels for asset '{asset.name}': {len(calc_channels)}\")\n", + "for cc in calc_channels:\n", + " print(f\" - {cc.name}\")\n", + " print(f\" Expression: {cc.expression}\")\n", + " print(f\" Version: {cc.version}\")" + ], + "id": "c3be1f869e83d59d" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Setting Rules\n", + "\n", + "Rules allow you to define conditions that trigger actions (like creating annotations) when met." + ], + "id": "f0e1d24d6fc507a2" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Create a rule that monitors a channel or calculated channel\n", + "# This example creates a rule that triggers when a value exceeds a threshold\n", + "\n", + "if calc_channel:\n", + " rule_name = f\"high_{calc_channel.name}_alert\"\n", + "\n", + " # Check if rule already exists\n", + " existing_rule = client.rules.find(name=rule_name)\n", + "\n", + " if existing_rule:\n", + " print(f\"Rule '{rule_name}' already exists\")\n", + " rule = existing_rule\n", + " else:\n", + " print(f\"Creating rule: {rule_name}\")\n", + "\n", + " rule = client.rules.create(\n", + " RuleCreate(\n", + " name=rule_name,\n", + " description=f\"Alert when {calc_channel.name} exceeds threshold\",\n", + " expression=\"$1 > 10\", # Adjust threshold as needed\n", + " channel_references=[\n", + " ChannelReference(\n", + " channel_reference=\"$1\",\n", + " channel_identifier=calc_channel.name\n", + " ),\n", + " ],\n", + " action=RuleAction.annotation(\n", + " annotation_type=RuleAnnotationType.DATA_REVIEW,\n", + " tags=[\"high_value\", \"alert\"],\n", + " default_assignee_user_id=None,\n", + " ),\n", + " asset_ids=[asset.id_],\n", + " )\n", + " )\n", + "\n", + " print(f\"✓ Created rule: {rule.name}\")\n", + " print(f\" ID: {rule.id_}\")\n", + " print(f\" Expression: {rule.expression}\")\n", + " print(f\" Enabled: {rule.is_enabled}\")\n", + "elif channels:\n", + " # Create a rule using a regular channel\n", + " channel = channels[0]\n", + " rule_name = f\"high_{channel.name}_alert\"\n", + "\n", + " existing_rule = client.rules.find(name=rule_name)\n", + "\n", + " if existing_rule:\n", + " print(f\"Rule '{rule_name}' already exists\")\n", + " rule = existing_rule\n", + " else:\n", + " print(f\"Creating rule: {rule_name}\")\n", + "\n", + " rule = client.rules.create(\n", + " RuleCreate(\n", + " name=rule_name,\n", + " description=f\"Alert when {channel.name} exceeds threshold\",\n", + " expression=\"$1 > 100\", # Adjust threshold as needed\n", + " channel_references=[\n", + " ChannelReference(\n", + " channel_reference=\"$1\",\n", + " channel_identifier=channel.name\n", + " ),\n", + " ],\n", + " action=RuleAction.annotation(\n", + " annotation_type=RuleAnnotationType.DATA_REVIEW,\n", + " tags=[\"threshold_exceeded\"],\n", + " default_assignee_user_id=None,\n", + " ),\n", + " asset_ids=[asset.id_],\n", + " )\n", + " )\n", + "\n", + " print(f\"✓ Created rule: {rule.name}\")\n", + "else:\n", + " print(\"No channels available to create a rule\")\n", + " rule = None" + ], + "id": "cd85739f690f302d" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# List all rules for the asset\n", + "rules = client.rules.list_(\n", + " asset_ids=[asset.id_],\n", + " limit=10\n", + ")\n", + "\n", + "print(f\"Rules for asset '{asset.name}': {len(rules)}\")\n", + "for r in rules:\n", + " status = \"Enabled\" if r.is_enabled else \"Disabled\"\n", + " print(f\" - {r.name} ({status})\")\n", + " print(f\" Expression: {r.expression}\")\n", + " if r.action:\n", + " print(f\" Action: {r.action.action_type.name}\")" + ], + "id": "3d53d29ebec3a241" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Summary\n", + "\n", + "This notebook demonstrated:\n", + "1. ✓ Initializing the Sift client with API credentials\n", + "2. ✓ Finding and filtering assets\n", + "3. ✓ Finding and filtering runs\n", + "4. ✓ Searching for channels by various criteria\n", + "5. ✓ Pulling time-series data as pandas DataFrames\n", + "6. ✓ Creating calculated channels with mathematical expressions\n", + "7. ✓ Setting up rules with conditions and actions\n", + "\n", + "### Next Steps\n", + "- Explore more filtering options for assets, runs, and channels\n", + "- Create more complex calculated channels with advanced expressions\n", + "- Set up rules with different action types (webhooks, etc.)\n", + "- Visualize the data using matplotlib or plotly\n", + "- Use the async API for better performance in production applications" + ], + "id": "ab250c26a5bfd825" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": [ + "# Optional: Clean up resources\n", + "# Uncomment to archive the created calculated channel and rule\n", + "\n", + "# if calc_channel:\n", + "# calc_channel.archive()\n", + "# print(f\"Archived calculated channel: {calc_channel.name}\")\n", + "\n", + "# if rule:\n", + "# rule.archive()\n", + "# print(f\"Archived rule: {rule.name}\")\n", + "\n", + "print(\"\\n✓ Example complete!\")" + ], + "id": "37b76600aedba1a1" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/docs/overrides/main.html b/python/docs/overrides/main.html index 648b7a6fe..4578fc92c 100644 --- a/python/docs/overrides/main.html +++ b/python/docs/overrides/main.html @@ -8,3 +8,13 @@ Click here to go to latest. {% endblock %} + +{% block content %} +{% if page.nb_url %} + + {% include ".icons/material/download.svg" %} + +{% endif %} + +{{ super() }} +{% endblock content %} diff --git a/python/examples/sift_client/assets/main.py b/python/examples/sift_client/assets/main.py deleted file mode 100644 index 77788bd92..000000000 --- a/python/examples/sift_client/assets/main.py +++ /dev/null @@ -1,27 +0,0 @@ -import os - -from dotenv import load_dotenv -from sift_client.client import SiftClient - - -def main(): - sift = SiftClient( - api_key=apikey, - rest_url="https://api.development.siftstack.com", - grpc_url="https://grpc-api.development.siftstack.com", - ) - - # Find an asset - asset = sift.assets.find(name_contains="Nostromo") - print(asset.tags) - asset.update(dict(tags=["simulator", "my_new_tag"])) - print(asset) - - -if __name__ == "__main__": - load_dotenv() - - apikey = os.getenv("SIFT_API_KEY") - assert apikey, "Missing 'SIFT_API_KEY' environment variable." - - main() diff --git a/python/examples/sift_client/ping/main.py b/python/examples/sift_client/ping/main.py deleted file mode 100644 index 42b1e4d0c..000000000 --- a/python/examples/sift_client/ping/main.py +++ /dev/null @@ -1,27 +0,0 @@ -import asyncio -import os - -from dotenv import load_dotenv -from sift_client.client import SiftClient - - -async def main(client): - print("Async in async loop:", await client.async_.ping.ping()) - print("Sync in async loop:", client.ping.ping()) - - -if __name__ == "__main__": - load_dotenv() - - apikey = os.getenv("SIFT_API_KEY") - assert apikey, "Missing 'SIFT_API_KEY' environment variable." - - sift = SiftClient( - api_key=apikey, - rest_url="https://api.development.siftstack.com", - grpc_url="https://grpc-api.development.siftstack.com", - ) - - asyncio.run(main(sift)) - - print("Sync:", sift.ping.ping()) diff --git a/python/lib/sift_client/sift_types/__init__.py b/python/lib/sift_client/sift_types/__init__.py index 1af4eb80d..ad96d4db5 100644 --- a/python/lib/sift_client/sift_types/__init__.py +++ b/python/lib/sift_client/sift_types/__init__.py @@ -1,3 +1,134 @@ +"""Sift Types - Pydantic models for Sift resources. + +This module provides strongly-typed Pydantic models for interacting with Sift resources. +These models are used throughout the Sift client to provide type safety, validation, +and convenient methods for working with Sift objects. + +## Resource BaseTypes + +Resource BaseTypes are immutable Pydantic models that represent specific Sift objects +retrieved from the API. They provide: + +- **Type-safe access** to all resource properties +- **Convenience methods** for common operations (update, archive, etc.) +- **Related resource access** via properties (e.g., `asset.runs`, `run.assets`) +- **Rich integration** with IDEs for autocomplete and type checking + +### Available Resource Types + +- `Asset` - Physical or logical entities (vehicles, machines, devices) +- `Run` - Time-bounded operational periods for an asset +- `Channel` - Time-series data streams (sensor readings, telemetry) +- etc. + + +## Create and Update Types + +Create and Update types are Pydantic models used to create new resources or modify +existing ones. They can be used directly as typed objects or as dictionaries for +convenience. + +### Create Types + +Create types define the required and optional fields for creating new resources. For example: + +- `RunCreate` - Create a new run +- `CalculatedChannelCreate` - Create a new calculated channel +- `RuleCreate` - Create a new rule +- etc. + +### Update Types + +Update types define which fields can be modified on existing resources. For example: + +- `AssetUpdate` - Update asset properties +- `RunUpdate` - Update run properties +- `CalculatedChannelUpdate` - Update calculated channel properties +- etc. + +### Example Usage + +```python +from sift_client import SiftClient +from sift_client.sift_types import RunCreate, AssetUpdate + +client = SiftClient(api_key="...", grpc_url="...", rest_url="...") + +# Using Create types - typed approach +run = client.runs.create( + RunCreate( + name="Test Run", + description="A test run", + asset_ids=["asset123"], + start_time=datetime.now(), + ) +) + +# Using Create types - dict approach (more convenient) +run = client.runs.create({ + "name": "Test Run", + "description": "A test run", + "asset_ids": ["asset123"], + "start_time": datetime.now(), +}) + +# Using Update types - typed approach +asset = client.assets.update( + asset="asset123", + update=AssetUpdate(tags=["production", "v2"]) +) + +# Using Update types - dict approach (more convenient) +asset = client.assets.update( + asset="asset123", + update={"tags": ["production", "v2"]} +) + +# Using convenience methods on resource instances +asset.update({"tags": ["production", "v3"]}) +``` + +## Helper Types + +Additional types are provided for specific use cases. For example: + +- `ChannelReference` - Reference to a channel in expressions +- `ChannelDataType` - Enum for channel data types +- `ChannelBitFieldElement` - Bit field element definition +- `RuleActionType` - Enum for rule action types +- `RuleAnnotationType` - Enum for annotation types +- `ChannelConfig` - Configuration for data ingestion channels +- `Flow` - Data flow configuration for ingestion +- `IngestionConfig` - Complete ingestion configuration +- etc. + +## Type Validation + +All types use Pydantic for validation, ensuring: + +- **Required fields** are present +- **Field types** are correct +- **Datetime fields** have timezone information +- **Enum values** are valid + +Validation errors are raised immediately with clear error messages. + +## Immutability + +Resource BaseTypes (Asset, Run, etc.) are immutable by default. To update a resource, +use the `update()` method, which will update the instance in-place by replacing its +internal state with the updated values from the API. + +```python +asset = client.assets.get(asset_id="asset123") +# This will raise an error - assets are immutable +# asset.name = "New Name" + +# Instead, use the update method +asset.update({"tags": ["new-tag"]}) # Updates the instance in-place +``` +""" + from sift_client.sift_types.asset import Asset, AssetUpdate from sift_client.sift_types.calculated_channel import ( CalculatedChannel, diff --git a/python/mkdocs.yml b/python/mkdocs.yml index 1644828f4..7e520bae6 100644 --- a/python/mkdocs.yml +++ b/python/mkdocs.yml @@ -54,7 +54,7 @@ extra: nav: - Home: index.md - Examples: - - examples/sift_client.ipynb + - examples/basic.ipynb - Sift Py API - Sift Client API (New) # - Guides: @@ -66,6 +66,9 @@ plugins: - autorefs - mike: # For docs versioning deploy_prefix: 'python' # In case we want to use doc sites for other client libs too + - mkdocs-jupyter: + include_source: True + execute: False - mkdocs-jupyter: include_source: True - mkdocstrings: From 10c86cce5c1b3f164b03c695f07a5848fdd70958 Mon Sep 17 00:00:00 2001 From: Alex Luck Date: Fri, 10 Oct 2025 14:36:40 -0700 Subject: [PATCH 2/6] update basic example --- python/docs/examples/basic.ipynb | 1453 ++++++++++++++++++++++-------- 1 file changed, 1102 insertions(+), 351 deletions(-) diff --git a/python/docs/examples/basic.ipynb b/python/docs/examples/basic.ipynb index 2a3e9de8e..62215551d 100644 --- a/python/docs/examples/basic.ipynb +++ b/python/docs/examples/basic.ipynb @@ -51,8 +51,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:41:13.634541Z", - "start_time": "2025-10-10T18:41:13.031402Z" + "end_time": "2025-10-10T21:24:39.373921Z", + "start_time": "2025-10-10T21:24:38.917998Z" } }, "cell_type": "code", @@ -86,8 +86,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:41:13.671729Z", - "start_time": "2025-10-10T18:41:13.639382Z" + "end_time": "2025-10-10T21:24:39.448172Z", + "start_time": "2025-10-10T21:24:39.388721Z" } }, "cell_type": "code", @@ -152,8 +152,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:41:16.613462Z", - "start_time": "2025-10-10T18:41:14.801033Z" + "end_time": "2025-10-10T21:24:40.911413Z", + "start_time": "2025-10-10T21:24:39.459910Z" } }, "cell_type": "code", @@ -212,8 +212,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:50:58.703512Z", - "start_time": "2025-10-10T18:50:58.635145Z" + "end_time": "2025-10-10T21:24:43.493121Z", + "start_time": "2025-10-10T21:24:43.390187Z" } }, "cell_type": "code", @@ -306,7 +306,7 @@ } } ], - "execution_count": 16 + "execution_count": 4 }, { "metadata": {}, @@ -317,8 +317,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:50:58.768704Z", - "start_time": "2025-10-10T18:50:58.712159Z" + "end_time": "2025-10-10T21:24:44.394852Z", + "start_time": "2025-10-10T21:24:44.336386Z" } }, "cell_type": "code", @@ -371,7 +371,7 @@ } } ], - "execution_count": 17 + "execution_count": 5 }, { "metadata": {}, @@ -382,8 +382,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:50:58.831165Z", - "start_time": "2025-10-10T18:50:58.773015Z" + "end_time": "2025-10-10T21:24:45.397172Z", + "start_time": "2025-10-10T21:24:45.336577Z" } }, "cell_type": "code", @@ -435,7 +435,7 @@ } } ], - "execution_count": 18 + "execution_count": 6 }, { "metadata": {}, @@ -443,95 +443,241 @@ "source": [ "### Creating, Updating, and Archiving\n", "\n", - "Most resources offer `create`, `update`, and `archive` methods. " + "Most resources offer `create`, `update`, and `archive` methods.\n", + "\n", + "Since `create` returns a `Run`, we can chain `update` and `archive` on it and the Sift object will update in-place." ], "id": "e8ebf9754df8f646" }, { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T18:51:57.257730Z", - "start_time": "2025-10-10T18:51:57.142330Z" + "end_time": "2025-10-10T21:24:46.553174Z", + "start_time": "2025-10-10T21:24:46.502236Z" } }, "cell_type": "code", "source": [ - "# List runs for the selected asset\n", - "runs = client.runs.list_(\n", - " assets=[asset.id_],\n", - " limit=10,\n", - " order_by=\"start_time desc\"\n", + "# Run creation\n", + "run = client.runs.create(dict(\n", + " name=\"Test Run\",\n", + " description=\"A test run\",\n", + " asset_ids=[asset.id_],\n", + " start_time=datetime.now())\n", ")\n", - "\n", - "print(f\"Found {len(runs)} runs for asset '{asset.name}':\")\n", - "for run in runs:\n", - " status = \"Running\" if run.stop_time is None else \"Stopped\"\n", - " print(f\" - {run.name} ({status})\")\n", - " print(f\" Start: {run.start_time}\")\n", - " if run.stop_time:\n", - " print(f\" Stop: {run.stop_time}\")" + "print(run)" ], - "id": "58645b9030c86cc4", + "id": "143bafd4b2a5edb5", "outputs": [ { - "ename": "AioRpcError", - "evalue": ":1:25: undeclared reference to 'asset_ids' (in container '')\n | is_archived == false && asset_ids in ['61d6e4f0-8287-4678-b071-18a95fcd9db6']\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"\n\tdebug_error_string = \"UNKNOWN:Error received from peer {created_time:\"2025-10-10T11:51:57.213813-07:00\", grpc_status:3, grpc_message:\"invalid argument: failed to compile filter: ERROR: :1:25: undeclared reference to \\'asset_ids\\' (in container \\'\\')\\n | is_archived == false && asset_ids in [\\'61d6e4f0-8287-4678-b071-18a95fcd9db6\\']\\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"}\"\n>", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mAioRpcError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[0;32mIn[20], line 2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;66;03m# List runs for the selected asset\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m runs \u001B[38;5;241m=\u001B[39m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mruns\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mlist_\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 3\u001B[0m \u001B[43m \u001B[49m\u001B[43massets\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43masset\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mid_\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 4\u001B[0m \u001B[43m \u001B[49m\u001B[43mlimit\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m10\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 5\u001B[0m \u001B[43m \u001B[49m\u001B[43morder_by\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mstart_time desc\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\n\u001B[1;32m 6\u001B[0m \u001B[43m)\u001B[49m\n\u001B[1;32m 8\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mFound \u001B[39m\u001B[38;5;132;01m{\u001B[39;00m\u001B[38;5;28mlen\u001B[39m(runs)\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m runs for asset \u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;132;01m{\u001B[39;00masset\u001B[38;5;241m.\u001B[39mname\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m:\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m 9\u001B[0m \u001B[38;5;28;01mfor\u001B[39;00m run \u001B[38;5;129;01min\u001B[39;00m runs:\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:72\u001B[0m, in \u001B[0;36mgenerate_sync_api.._make_sync..sync_func\u001B[0;34m(self, *a, **kw)\u001B[0m\n\u001B[1;32m 70\u001B[0m \u001B[38;5;129m@wraps\u001B[39m(async_func)\n\u001B[1;32m 71\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21msync_func\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39ma, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkw):\n\u001B[0;32m---> 72\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_run\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mgetattr\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_async_impl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfunc_name\u001B[49m\u001B[43m)\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43ma\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkw\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:56\u001B[0m, in \u001B[0;36mgenerate_sync_api.._run\u001B[0;34m(self, coro)\u001B[0m\n\u001B[1;32m 54\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_run\u001B[39m(\u001B[38;5;28mself\u001B[39m, coro):\n\u001B[1;32m 55\u001B[0m loop \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_async_impl\u001B[38;5;241m.\u001B[39mclient\u001B[38;5;241m.\u001B[39mget_asyncio_loop()\n\u001B[0;32m---> 56\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43masyncio\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrun_coroutine_threadsafe\u001B[49m\u001B[43m(\u001B[49m\u001B[43mcoro\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mloop\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mresult\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:444\u001B[0m, in \u001B[0;36mFuture.result\u001B[0;34m(self, timeout)\u001B[0m\n\u001B[1;32m 442\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m CancelledError()\n\u001B[1;32m 443\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_state \u001B[38;5;241m==\u001B[39m FINISHED:\n\u001B[0;32m--> 444\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__get_result\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 445\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 446\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTimeoutError\u001B[39;00m()\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:389\u001B[0m, in \u001B[0;36mFuture.__get_result\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 387\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception:\n\u001B[1;32m 388\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 389\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception\n\u001B[1;32m 390\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n\u001B[1;32m 391\u001B[0m \u001B[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001B[39;00m\n\u001B[1;32m 392\u001B[0m \u001B[38;5;28mself\u001B[39m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/resources/runs.py:171\u001B[0m, in \u001B[0;36mRunsAPIAsync.list_\u001B[0;34m(self, name, name_contains, name_regex, run_ids, client_keys, created_after, created_before, modified_after, modified_before, created_by, modified_by, metadata, assets, duration_less_than, duration_greater_than, start_time_after, start_time_before, stop_time_after, stop_time_before, is_stopped, description_contains, include_archived, filter_query, order_by, limit)\u001B[0m\n\u001B[1;32m 168\u001B[0m filter_parts\u001B[38;5;241m.\u001B[39mappend(cel\u001B[38;5;241m.\u001B[39mnot_(cel\u001B[38;5;241m.\u001B[39mequals_null(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mstop_time\u001B[39m\u001B[38;5;124m\"\u001B[39m)))\n\u001B[1;32m 169\u001B[0m query_filter \u001B[38;5;241m=\u001B[39m cel\u001B[38;5;241m.\u001B[39mand_(\u001B[38;5;241m*\u001B[39mfilter_parts)\n\u001B[0;32m--> 171\u001B[0m runs \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_low_level_client\u001B[38;5;241m.\u001B[39mlist_all_runs(\n\u001B[1;32m 172\u001B[0m query_filter\u001B[38;5;241m=\u001B[39mquery_filter \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 173\u001B[0m order_by\u001B[38;5;241m=\u001B[39morder_by,\n\u001B[1;32m 174\u001B[0m max_results\u001B[38;5;241m=\u001B[39mlimit,\n\u001B[1;32m 175\u001B[0m )\n\u001B[1;32m 176\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_apply_client_to_instances(runs)\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/runs.py:114\u001B[0m, in \u001B[0;36mRunsLowLevelClient.list_all_runs\u001B[0;34m(self, query_filter, order_by, max_results)\u001B[0m\n\u001B[1;32m 97\u001B[0m \u001B[38;5;28;01masync\u001B[39;00m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mlist_all_runs\u001B[39m(\n\u001B[1;32m 98\u001B[0m \u001B[38;5;28mself\u001B[39m,\n\u001B[1;32m 99\u001B[0m \u001B[38;5;241m*\u001B[39m,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 102\u001B[0m max_results: \u001B[38;5;28mint\u001B[39m \u001B[38;5;241m|\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 103\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mlist\u001B[39m[Run]:\n\u001B[1;32m 104\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"List all runs with optional filtering.\u001B[39;00m\n\u001B[1;32m 105\u001B[0m \n\u001B[1;32m 106\u001B[0m \u001B[38;5;124;03m Args:\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 112\u001B[0m \u001B[38;5;124;03m A list of all matching runs.\u001B[39;00m\n\u001B[1;32m 113\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n\u001B[0;32m--> 114\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_handle_pagination(\n\u001B[1;32m 115\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mlist_runs,\n\u001B[1;32m 116\u001B[0m kwargs\u001B[38;5;241m=\u001B[39m{\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mquery_filter\u001B[39m\u001B[38;5;124m\"\u001B[39m: query_filter},\n\u001B[1;32m 117\u001B[0m order_by\u001B[38;5;241m=\u001B[39morder_by,\n\u001B[1;32m 118\u001B[0m max_results\u001B[38;5;241m=\u001B[39mmax_results,\n\u001B[1;32m 119\u001B[0m )\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/base.py:41\u001B[0m, in \u001B[0;36mLowLevelClientBase._handle_pagination\u001B[0;34m(func, kwargs, page_size, page_token, order_by, max_results)\u001B[0m\n\u001B[1;32m 39\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m max_results \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;28mlen\u001B[39m(results) \u001B[38;5;241m>\u001B[39m\u001B[38;5;241m=\u001B[39m max_results:\n\u001B[1;32m 40\u001B[0m \u001B[38;5;28;01mbreak\u001B[39;00m\n\u001B[0;32m---> 41\u001B[0m response, page_token \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m func(\n\u001B[1;32m 42\u001B[0m page_size\u001B[38;5;241m=\u001B[39mpage_size,\n\u001B[1;32m 43\u001B[0m page_token\u001B[38;5;241m=\u001B[39mpage_token,\n\u001B[1;32m 44\u001B[0m order_by\u001B[38;5;241m=\u001B[39morder_by,\n\u001B[1;32m 45\u001B[0m \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs,\n\u001B[1;32m 46\u001B[0m )\n\u001B[1;32m 47\u001B[0m results\u001B[38;5;241m.\u001B[39mextend(response)\n\u001B[1;32m 48\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m page_token \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/runs.py:91\u001B[0m, in \u001B[0;36mRunsLowLevelClient.list_runs\u001B[0;34m(self, page_size, page_token, query_filter, order_by)\u001B[0m\n\u001B[1;32m 88\u001B[0m request_kwargs[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124morder_by\u001B[39m\u001B[38;5;124m\"\u001B[39m] \u001B[38;5;241m=\u001B[39m order_by\n\u001B[1;32m 90\u001B[0m request \u001B[38;5;241m=\u001B[39m ListRunsRequest(\u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mrequest_kwargs)\n\u001B[0;32m---> 91\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grpc_client\u001B[38;5;241m.\u001B[39mget_stub(RunServiceStub)\u001B[38;5;241m.\u001B[39mListRuns(request)\n\u001B[1;32m 92\u001B[0m response \u001B[38;5;241m=\u001B[39m cast(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mListRunsResponse\u001B[39m\u001B[38;5;124m\"\u001B[39m, response)\n\u001B[1;32m 94\u001B[0m runs \u001B[38;5;241m=\u001B[39m [Run\u001B[38;5;241m.\u001B[39m_from_proto(run) \u001B[38;5;28;01mfor\u001B[39;00m run \u001B[38;5;129;01min\u001B[39;00m response\u001B[38;5;241m.\u001B[39mruns]\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_interceptor.py:472\u001B[0m, in \u001B[0;36m_InterceptedUnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 470\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__await__\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[1;32m 471\u001B[0m call \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_interceptors_task\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[0;32m--> 472\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m call\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[1;32m 473\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_call.py:327\u001B[0m, in \u001B[0;36m_UnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 325\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m asyncio\u001B[38;5;241m.\u001B[39mCancelledError()\n\u001B[1;32m 326\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 327\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m _create_rpc_error(\n\u001B[1;32m 328\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_initial_metadata,\n\u001B[1;32m 329\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_status,\n\u001B[1;32m 330\u001B[0m )\n\u001B[1;32m 331\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 332\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", - "\u001B[0;31mAioRpcError\u001B[0m: :1:25: undeclared reference to 'asset_ids' (in container '')\n | is_archived == false && asset_ids in ['61d6e4f0-8287-4678-b071-18a95fcd9db6']\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"\n\tdebug_error_string = \"UNKNOWN:Error received from peer {created_time:\"2025-10-10T11:51:57.213813-07:00\", grpc_status:3, grpc_message:\"invalid argument: failed to compile filter: ERROR: :1:25: undeclared reference to \\'asset_ids\\' (in container \\'\\')\\n | is_archived == false && asset_ids in [\\'61d6e4f0-8287-4678-b071-18a95fcd9db6\\']\\n | ........................^ (a4aa7f59-a7f8-4026-b602-eeb00912c845)\"}\"\n>" - ] + "data": { + "text/plain": [ + "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'21d845a4-2d70-45e6-b741-afce68878134'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'Test Run'\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'A test run'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m508353\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m510091\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", + " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m502969\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m8602\u001B[0m\u001B[1m)\u001B[0m,\n", + " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'74213648-793f-4023-a4c8-ba3f81af94c1'\u001B[0m,\n", + " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Run(\n",
+       "    id_='21d845a4-2d70-45e6-b741-afce68878134',\n",
+       "    name='Test Run',\n",
+       "    description='A test run',\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 508353, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 510091, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    metadata={},\n",
+       "    tags=[],\n",
+       "    asset_ids=[],\n",
+       "    is_adhoc=False,\n",
+       "    is_archived=False,\n",
+       "    start_time=datetime.datetime(2025, 10, 10, 14, 24, 46, 502969, tzinfo=datetime.timezone.utc),\n",
+       "    stop_time=None,\n",
+       "    duration=datetime.timedelta(seconds=25200, microseconds=8602),\n",
+       "    default_report_id='74213648-793f-4023-a4c8-ba3f81af94c1',\n",
+       "    client_key=None,\n",
+       "    archived_date=None\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } } ], - "execution_count": 20 + "execution_count": 7 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:24:47.415518Z", + "start_time": "2025-10-10T21:24:47.357814Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ - "# Get a specific run\n", - "if runs:\n", - " run = runs[0]\n", - " print(f\"✓ Selected run: {run.name}\")\n", - " print(f\" ID: {run.id_}\")\n", - " print(f\" Start time: {run.start_time}\")\n", - " print(f\" Stop time: {run.stop_time or 'Still running'}\")\n", - "else:\n", - " print(\"No runs found for this asset\")\n", - " run = None" + "# Run update\n", + "run.update(dict(\n", + " name=\"Updated Test Run\",\n", + " description=\"An updated test run\", )\n", + ")\n", + "print(run)" + ], + "id": "22ad6199aeb8cc5d", + "outputs": [ + { + "data": { + "text/plain": [ + "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'21d845a4-2d70-45e6-b741-afce68878134'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'Updated Test Run'\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'An updated test run'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m508353\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m47\u001B[0m, \u001B[1;36m369552\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", + " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m502969\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m870395\u001B[0m\u001B[1m)\u001B[0m,\n", + " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'74213648-793f-4023-a4c8-ba3f81af94c1'\u001B[0m,\n", + " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Run(\n",
+       "    id_='21d845a4-2d70-45e6-b741-afce68878134',\n",
+       "    name='Updated Test Run',\n",
+       "    description='An updated test run',\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 508353, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 24, 47, 369552, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    metadata={},\n",
+       "    tags=[],\n",
+       "    asset_ids=[],\n",
+       "    is_adhoc=False,\n",
+       "    is_archived=False,\n",
+       "    start_time=datetime.datetime(2025, 10, 10, 14, 24, 46, 502969, tzinfo=datetime.timezone.utc),\n",
+       "    stop_time=None,\n",
+       "    duration=datetime.timedelta(seconds=25200, microseconds=870395),\n",
+       "    default_report_id='74213648-793f-4023-a4c8-ba3f81af94c1',\n",
+       "    client_key=None,\n",
+       "    archived_date=None\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } ], - "id": "76b25f66938cf1b6" + "execution_count": 8 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:24:48.150939Z", + "start_time": "2025-10-10T21:24:48.085422Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ - "# Filter runs by time range\n", - "recent_runs = client.runs.list_(\n", - " assets=[asset.id_],\n", - " start_time_after=datetime.now() - timedelta(days=7),\n", - " limit=5\n", - ")\n", - "\n", - "print(f\"Runs started in the last 7 days: {len(recent_runs)}\")" + "# Run archive\n", + "run.archive()\n", + "print(run)" + ], + "id": "3d24afef7771f010", + "outputs": [ + { + "data": { + "text/plain": [ + "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'21d845a4-2d70-45e6-b741-afce68878134'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'Updated Test Run'\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'An updated test run'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m508353\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m48\u001B[0m, \u001B[1;36m102385\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", + " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33mis_archived\u001B[0m=\u001B[3;92mTrue\u001B[0m,\n", + " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m502969\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25201\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m605088\u001B[0m\u001B[1m)\u001B[0m,\n", + " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'74213648-793f-4023-a4c8-ba3f81af94c1'\u001B[0m,\n", + " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m48\u001B[0m, \u001B[1;36m98579\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Run(\n",
+       "    id_='21d845a4-2d70-45e6-b741-afce68878134',\n",
+       "    name='Updated Test Run',\n",
+       "    description='An updated test run',\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 508353, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 24, 48, 102385, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    metadata={},\n",
+       "    tags=[],\n",
+       "    asset_ids=[],\n",
+       "    is_adhoc=False,\n",
+       "    is_archived=True,\n",
+       "    start_time=datetime.datetime(2025, 10, 10, 14, 24, 46, 502969, tzinfo=datetime.timezone.utc),\n",
+       "    stop_time=None,\n",
+       "    duration=datetime.timedelta(seconds=25201, microseconds=605088),\n",
+       "    default_report_id='74213648-793f-4023-a4c8-ba3f81af94c1',\n",
+       "    client_key=None,\n",
+       "    archived_date=datetime.datetime(2025, 10, 10, 21, 24, 48, 98579, tzinfo=datetime.timezone.utc)\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } ], - "id": "15c0bca4bde0101b" + "execution_count": 9 }, { "metadata": {}, @@ -544,32 +690,277 @@ "id": "c1830f179b22cb43" }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:24:49.389722Z", + "start_time": "2025-10-10T21:24:49.255833Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ "# List channels for the selected asset\n", "channels = client.channels.list_(\n", " asset=asset.id_,\n", - " limit=20\n", + " limit=5\n", ")\n", "\n", "print(f\"Found {len(channels)} channels for asset '{asset.name}':\")\n", - "for channel in channels[:10]: # Show first 10\n", - " print(f\" - {channel.name}\")\n", - " if channel.description:\n", - " print(f\" Description: {channel.description}\")\n", - " if channel.units:\n", - " print(f\" Units: {channel.units}\")" - ], - "id": "9c5a1b60c0fce9fc" + "for channel in channels: # Show first 10\n", + " print(channel)\n", + " # if channel.description:\n", + " # print(f\" Description: {channel.description}\")\n", + " # if channel.units:\n", + " # print(f\" Units: {channel.units}\")" + ], + "id": "9c5a1b60c0fce9fc", + "outputs": [ + { + "data": { + "text/plain": [ + "Found \u001B[1;36m5\u001B[0m channels for asset \u001B[32m'MarsRover0'\u001B[0m:\n" + ], + "text/html": [ + "
Found 5 channels for asset 'MarsRover0':\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'0f1a32d4-0f97-494f-82f8-2ed7f3983e74'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'is_even'\u001B[0m,\n", + " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.BOOL:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m5\u001B[0m\u001B[1m>\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'is the value of milliseconds even'\u001B[0m,\n", + " \u001B[33munit\u001B[0m=\u001B[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001B[0m,\n", + " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Channel(\n",
+       "    id_='0f1a32d4-0f97-494f-82f8-2ed7f3983e74',\n",
+       "    name='is_even',\n",
+       "    data_type=<ChannelDataType.BOOL: 5>,\n",
+       "    description='is the value of milliseconds even',\n",
+       "    unit='0c359676-c6c9-47d3-acca-d8e938311b2a',\n",
+       "    bit_field_elements=[],\n",
+       "    enum_types={},\n",
+       "    asset_id='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'1c2dd815-2c9e-4801-92dc-1f65cad2114b'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'voltage'\u001B[0m,\n", + " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.INT_32:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m7\u001B[0m\u001B[1m>\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'voltage at the source'\u001B[0m,\n", + " \u001B[33munit\u001B[0m=\u001B[32m'09f1005b-df6a-4f82-838f-c57e77c587ef'\u001B[0m,\n", + " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Channel(\n",
+       "    id_='1c2dd815-2c9e-4801-92dc-1f65cad2114b',\n",
+       "    name='voltage',\n",
+       "    data_type=<ChannelDataType.INT_32: 7>,\n",
+       "    description='voltage at the source',\n",
+       "    unit='09f1005b-df6a-4f82-838f-c57e77c587ef',\n",
+       "    bit_field_elements=[],\n",
+       "    enum_types={},\n",
+       "    asset_id='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'606817a0-396e-4575-9ffc-45a4ef9ca66a'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'log'\u001B[0m,\n", + " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.STRING:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m2\u001B[0m\u001B[1m>\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'this simulates log files'\u001B[0m,\n", + " \u001B[33munit\u001B[0m=\u001B[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001B[0m,\n", + " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Channel(\n",
+       "    id_='606817a0-396e-4575-9ffc-45a4ef9ca66a',\n",
+       "    name='log',\n",
+       "    data_type=<ChannelDataType.STRING: 2>,\n",
+       "    description='this simulates log files',\n",
+       "    unit='0c359676-c6c9-47d3-acca-d8e938311b2a',\n",
+       "    bit_field_elements=[],\n",
+       "    enum_types={},\n",
+       "    asset_id='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'mainmotor.velocity'\u001B[0m,\n", + " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.DOUBLE:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m1\u001B[0m\u001B[1m>\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'speed'\u001B[0m,\n", + " \u001B[33munit\u001B[0m=\u001B[32m'b840c8e8-33fb-433c-9448-07577f04e990'\u001B[0m,\n", + " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Channel(\n",
+       "    id_='a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7',\n",
+       "    name='mainmotor.velocity',\n",
+       "    data_type=<ChannelDataType.DOUBLE: 1>,\n",
+       "    description='speed',\n",
+       "    unit='b840c8e8-33fb-433c-9448-07577f04e990',\n",
+       "    bit_field_elements=[],\n",
+       "    enum_types={},\n",
+       "    asset_id='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'c052cef4-d3eb-486e-b3cb-63b59504e913'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'gpio'\u001B[0m,\n", + " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.BIT_FIELD:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m4\u001B[0m\u001B[1m>\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'on/off values for pins on gpio'\u001B[0m,\n", + " \u001B[33munit\u001B[0m=\u001B[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001B[0m,\n", + " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\n", + " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'12v'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m0\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m1\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'charge'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m1\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m2\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'led'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m3\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m4\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'heater'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m7\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m1\u001B[0m\u001B[1m}\u001B[0m\n", + " \u001B[1m]\u001B[0m,\n", + " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Channel(\n",
+       "    id_='c052cef4-d3eb-486e-b3cb-63b59504e913',\n",
+       "    name='gpio',\n",
+       "    data_type=<ChannelDataType.BIT_FIELD: 4>,\n",
+       "    description='on/off values for pins on gpio',\n",
+       "    unit='0c359676-c6c9-47d3-acca-d8e938311b2a',\n",
+       "    bit_field_elements=[\n",
+       "        {'name': '12v', 'index': 0, 'bit_count': 1},\n",
+       "        {'name': 'charge', 'index': 1, 'bit_count': 2},\n",
+       "        {'name': 'led', 'index': 3, 'bit_count': 4},\n",
+       "        {'name': 'heater', 'index': 7, 'bit_count': 1}\n",
+       "    ],\n",
+       "    enum_types={},\n",
+       "    asset_id='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 10 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:24:50.361561Z", + "start_time": "2025-10-10T21:24:50.299511Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ "# Search for specific channels by name pattern\n", "# Replace with a pattern that matches your channel names\n", @@ -581,17 +972,81 @@ "\n", "print(f\"Channels containing 'velocity': {len(velocity_channels)}\")\n", "for ch in velocity_channels:\n", - " print(f\" - {ch.name}\")" + " print(ch)" + ], + "id": "c2317d7f561926d6", + "outputs": [ + { + "data": { + "text/plain": [ + "Channels containing \u001B[32m'velocity'\u001B[0m: \u001B[1;36m1\u001B[0m\n" + ], + "text/html": [ + "
Channels containing 'velocity': 1\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'mainmotor.velocity'\u001B[0m,\n", + " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.DOUBLE:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m1\u001B[0m\u001B[1m>\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'speed'\u001B[0m,\n", + " \u001B[33munit\u001B[0m=\u001B[32m'b840c8e8-33fb-433c-9448-07577f04e990'\u001B[0m,\n", + " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
Channel(\n",
+       "    id_='a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7',\n",
+       "    name='mainmotor.velocity',\n",
+       "    data_type=<ChannelDataType.DOUBLE: 1>,\n",
+       "    description='speed',\n",
+       "    unit='b840c8e8-33fb-433c-9448-07577f04e990',\n",
+       "    bit_field_elements=[],\n",
+       "    enum_types={},\n",
+       "    asset_id='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
+       "    created_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 3, 4, 19, 51, 15, 89746, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d',\n",
+       "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } ], - "id": "c2317d7f561926d6" + "execution_count": 11 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:24:51.506365Z", + "start_time": "2025-10-10T21:24:51.460199Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ - "# Get channels for a specific run\n", + "# Get channels for a specific run. There should be none since we just created it.\n", "if run:\n", " run_channels = client.channels.list_(\n", " run=run.id_,\n", @@ -601,7 +1056,26 @@ " for ch in run_channels:\n", " print(f\" - {ch.name}\")" ], - "id": "1601a55853281e95" + "id": "1601a55853281e95", + "outputs": [ + { + "data": { + "text/plain": [ + "Channels in run \u001B[32m'Updated Test Run'\u001B[0m: \u001B[1;36m0\u001B[0m\n" + ], + "text/html": [ + "
Channels in run 'Updated Test Run': 0\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 12 }, { "metadata": {}, @@ -614,66 +1088,295 @@ "id": "7c611ee731605cbd" }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:31:53.467442Z", + "start_time": "2025-10-10T21:31:52.933530Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ + "run = client.runs.list_(duration_greater_than=timedelta(seconds=30),\n", + " description_contains=\"simulated run: 1 flows, 8 total channels, 5hz sampling rate\")[0]\n", + "\n", "# Get data for specific channels\n", - "if channels and run:\n", - " # Select first 3 channels for this example\n", - " selected_channels = channels[:3]\n", "\n", - " print(f\"Fetching data for {len(selected_channels)} channels...\")\n", "\n", - " # Get data as a dictionary of pandas DataFrames\n", - " data = client.channels.get_data(\n", - " channels=selected_channels,\n", - " run=run.id_,\n", - " limit=1000 # Limit to 1000 data points per channel\n", - " )\n", + "# Get data as a dictionary of pandas DataFrames\n", + "data = client.channels.get_data(\n", + " channels=client.channels.list_(run=run, name_contains=\"v\"),\n", + " run=run,\n", + " limit=1000 # Limit to 1000 data points per channel\n", + ")\n", "\n", - " print(f\"\\n✓ Retrieved data for {len(data)} channels:\")\n", - " for channel_name, df in data.items():\n", - " print(f\"\\n Channel: {channel_name}\")\n", - " print(f\" Data points: {len(df)}\")\n", - " if len(df) > 0:\n", - " print(f\" Columns: {list(df.columns)}\")\n", - " print(f\" Sample data:\")\n", - " print(df.head())\n", - "else:\n", - " print(\"No channels or run available to fetch data\")" + "print(f\"\\n✓ Retrieved data for {len(data)} channels:\")\n", + "for channel_name, df in data.items():\n", + " print(f\"\\n Channel: {channel_name}\")\n", + " print(f\" Data points: {len(df)}\")\n", + " print(df.head())\n" ], - "id": "b6b40678b0bbe34e" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Get data for a specific time range\n", - "if channels and run and run.start_time:\n", - " selected_channels = channels[:2]\n", - "\n", - " # Get data for first hour of the run\n", - " start_time = run.start_time\n", - " end_time = start_time + timedelta(hours=1)\n", - "\n", - " print(f\"Fetching data from {start_time} to {end_time}...\")\n", - "\n", - " data = client.channels.get_data(\n", - " channels=selected_channels,\n", - " run=run.id_,\n", - " start_time=start_time,\n", - " end_time=end_time\n", - " )\n", - "\n", - " print(f\"\\n✓ Retrieved time-ranged data:\")\n", - " for channel_name, df in data.items():\n", - " print(f\" {channel_name}: {len(df)} data points\")" + "id": "b6b40678b0bbe34e", + "outputs": [ + { + "data": { + "text/plain": [ + "\n", + "✓ Retrieved data for \u001B[1;36m4\u001B[0m channels:\n" + ], + "text/html": [ + "
\n",
+       "✓ Retrieved data for 4 channels:\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\n", + " Channel: is_even\n" + ], + "text/html": [ + "
\n",
+       "  Channel: is_even\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " Data points: \u001B[1;36m1000\u001B[0m\n" + ], + "text/html": [ + "
  Data points: 1000\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " is_even\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n" + ], + "text/html": [ + "
                                     is_even\n",
+       "2025-06-04 17:21:13.180486958+00:00     True\n",
+       "2025-06-04 17:21:13.380486958+00:00     True\n",
+       "2025-06-04 17:21:13.580486958+00:00     True\n",
+       "2025-06-04 17:21:13.780486958+00:00     True\n",
+       "2025-06-04 17:21:13.980486958+00:00     True\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\n", + " Channel: mainmotor.velocity\n" + ], + "text/html": [ + "
\n",
+       "  Channel: mainmotor.velocity\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " Data points: \u001B[1;36m1000\u001B[0m\n" + ], + "text/html": [ + "
  Data points: 1000\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " mainmotor.velocity\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m21.352492\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m32.011998\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m34.370449\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m25.635827\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m16.148490\u001B[0m\n" + ], + "text/html": [ + "
                                     mainmotor.velocity\n",
+       "2025-06-04 17:21:13.180486958+00:00           21.352492\n",
+       "2025-06-04 17:21:13.380486958+00:00           32.011998\n",
+       "2025-06-04 17:21:13.580486958+00:00           34.370449\n",
+       "2025-06-04 17:21:13.780486958+00:00           25.635827\n",
+       "2025-06-04 17:21:13.980486958+00:00           16.148490\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\n", + " Channel: vehicle_state\n" + ], + "text/html": [ + "
\n",
+       "  Channel: vehicle_state\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " Data points: \u001B[1;36m1000\u001B[0m\n" + ], + "text/html": [ + "
  Data points: 1000\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " vehicle_state\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n" + ], + "text/html": [ + "
                                     vehicle_state\n",
+       "2025-06-04 17:21:13.180486958+00:00              1\n",
+       "2025-06-04 17:21:13.380486958+00:00              1\n",
+       "2025-06-04 17:21:13.580486958+00:00              1\n",
+       "2025-06-04 17:21:13.780486958+00:00              1\n",
+       "2025-06-04 17:21:13.980486958+00:00              1\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\n", + " Channel: voltage\n" + ], + "text/html": [ + "
\n",
+       "  Channel: voltage\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " Data points: \u001B[1;36m1000\u001B[0m\n" + ], + "text/html": [ + "
  Data points: 1000\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " voltage\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m12\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m12\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m12\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m2\u001B[0m\n", + "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m2\u001B[0m\n" + ], + "text/html": [ + "
                                     voltage\n",
+       "2025-06-04 17:21:13.180486958+00:00       12\n",
+       "2025-06-04 17:21:13.380486958+00:00       12\n",
+       "2025-06-04 17:21:13.580486958+00:00       12\n",
+       "2025-06-04 17:21:13.780486958+00:00        2\n",
+       "2025-06-04 17:21:13.980486958+00:00        2\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } ], - "id": "258bccc4cd8868e2" + "execution_count": 21 }, { "metadata": {}, @@ -686,72 +1389,158 @@ "id": "b6c81e31a31fdc03" }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:34:03.552648Z", + "start_time": "2025-10-10T21:34:03.416644Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ "# Create a calculated channel\n", "# This example creates a channel that divides two existing channels\n", "# Replace channel names with actual channels from your system\n", "\n", - "if len(channels) >= 2:\n", - " # Use first two channels for this example\n", - " channel1 = channels[0]\n", - " channel2 = channels[1]\n", "\n", - " calc_channel_name = f\"{channel1.name}_per_{channel2.name}\"\n", + "# Use first two channels for this example\n", + "channel1 = channels[0]\n", + "channel2 = channels[1]\n", "\n", - " # Check if calculated channel already exists\n", - " existing = client.calculated_channels.find(\n", - " name=calc_channel_name,\n", - " asset=asset.id_\n", - " )\n", + "calc_channel_name = f\"{channel1.name}_per_{channel2.name}\"\n", "\n", - " if existing:\n", - " print(f\"Calculated channel '{calc_channel_name}' already exists\")\n", - " calc_channel = existing\n", - " else:\n", - " print(f\"Creating calculated channel: {calc_channel_name}\")\n", - "\n", - " calc_channel = client.calculated_channels.create(\n", - " CalculatedChannelCreate(\n", - " name=calc_channel_name,\n", - " description=f\"Ratio of {channel1.name} to {channel2.name}\",\n", - " expression=\"$1 / $2\", # $1 and $2 refer to the channel references below\n", - " channel_references=[\n", - " ChannelReference(\n", - " channel_reference=\"$1\",\n", - " channel_identifier=channel1.name\n", - " ),\n", - " ChannelReference(\n", - " channel_reference=\"$2\",\n", - " channel_identifier=channel2.name\n", - " ),\n", - " ],\n", - " units=f\"{channel1.units or 'unit1'}/{channel2.units or 'unit2'}\",\n", - " asset_ids=[asset.id_],\n", - " )\n", - " )\n", + "# Check if calculated channel already exists\n", + "existing = client.calculated_channels.find(\n", + " name=calc_channel_name,\n", + " asset=asset.id_\n", + ")\n", "\n", - " print(f\"✓ Created calculated channel: {calc_channel.name}\")\n", - " print(f\" ID: {calc_channel.id_}\")\n", - " print(f\" Expression: {calc_channel.expression}\")\n", + "if existing:\n", + " print(f\"Calculated channel '{calc_channel_name}' already exists\")\n", + " calc_channel = existing\n", "else:\n", - " print(\"Not enough channels available to create a calculated channel\")\n", - " calc_channel = None" + " print(f\"Creating calculated channel: {calc_channel_name}\")\n", + "\n", + " calc_channel = client.calculated_channels.create(\n", + " dict(\n", + " name=calc_channel_name,\n", + " description=f\"Ratio of {channel1.name} to {channel2.name}\",\n", + " expression=\"$1 / $2\", # $1 and $2 refer to the channel references below\n", + " expression_channel_references=[\n", + " dict(\n", + " channel_reference=\"$1\",\n", + " channel_identifier=channel1.name\n", + " ),\n", + " dict(\n", + " channel_reference=\"$2\",\n", + " channel_identifier=channel2.name\n", + " ),\n", + " ],\n", + " asset_ids=[asset.id_],\n", + " )\n", + " )\n", + "\n", + " print(calc_channel)\n" + ], + "id": "70a5b0d39e5230c4", + "outputs": [ + { + "data": { + "text/plain": [ + "Creating calculated channel: is_even_per_voltage\n" + ], + "text/html": [ + "
Creating calculated channel: is_even_per_voltage\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\u001B[1;35mCalculatedChannel\u001B[0m\u001B[1m(\u001B[0m\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'd283b5fe-fed5-4260-93d1-8bd65bec4bfe'\u001B[0m,\n", + " \u001B[33mname\u001B[0m=\u001B[32m'is_even_per_voltage'\u001B[0m,\n", + " \u001B[33mdescription\u001B[0m=\u001B[32m'Ratio of is_even to voltage'\u001B[0m,\n", + " \u001B[33mexpression\u001B[0m=\u001B[32m'$1 / $2'\u001B[0m,\n", + " \u001B[33mchannel_references\u001B[0m=\u001B[1m[\u001B[0m\n", + " \u001B[1m{\u001B[0m\u001B[32m'channel_reference'\u001B[0m: \u001B[32m'$1'\u001B[0m, \u001B[32m'channel_identifier'\u001B[0m: \u001B[32m'is_even'\u001B[0m\u001B[1m}\u001B[0m,\n", + " \u001B[1m{\u001B[0m\u001B[32m'channel_reference'\u001B[0m: \u001B[32m'$2'\u001B[0m, \u001B[32m'channel_identifier'\u001B[0m: \u001B[32m'voltage'\u001B[0m\u001B[1m}\u001B[0m\n", + " \u001B[1m]\u001B[0m,\n", + " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33munits\u001B[0m=\u001B[32m''\u001B[0m,\n", + " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mtag_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", + " \u001B[33mall_assets\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", + " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", + " \u001B[33mclient_key\u001B[0m=\u001B[32m''\u001B[0m,\n", + " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", + " \u001B[33mversion_id\u001B[0m=\u001B[32m'0923ec64-9799-4e73-8038-71496227a846'\u001B[0m,\n", + " \u001B[33mversion\u001B[0m=\u001B[1;36m1\u001B[0m,\n", + " \u001B[33mchange_message\u001B[0m=\u001B[32m'Created calculated channel'\u001B[0m,\n", + " \u001B[33muser_notes\u001B[0m=\u001B[32m''\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m34\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m533939\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m34\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m533939\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", + " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m\n", + "\u001B[1m)\u001B[0m\n" + ], + "text/html": [ + "
CalculatedChannel(\n",
+       "    id_='d283b5fe-fed5-4260-93d1-8bd65bec4bfe',\n",
+       "    name='is_even_per_voltage',\n",
+       "    description='Ratio of is_even to voltage',\n",
+       "    expression='$1 / $2',\n",
+       "    channel_references=[\n",
+       "        {'channel_reference': '$1', 'channel_identifier': 'is_even'},\n",
+       "        {'channel_reference': '$2', 'channel_identifier': 'voltage'}\n",
+       "    ],\n",
+       "    is_archived=False,\n",
+       "    units='',\n",
+       "    asset_ids=['61d6e4f0-8287-4678-b071-18a95fcd9db6'],\n",
+       "    tag_ids=[],\n",
+       "    all_assets=False,\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    client_key='',\n",
+       "    archived_date=None,\n",
+       "    version_id='0923ec64-9799-4e73-8038-71496227a846',\n",
+       "    version=1,\n",
+       "    change_message='Created calculated channel',\n",
+       "    user_notes='',\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 34, 3, 533939, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 34, 3, 533939, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c'\n",
+       ")\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } ], - "id": "70a5b0d39e5230c4" + "execution_count": 23 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:35:07.418677Z", + "start_time": "2025-10-10T21:35:07.170355Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ "# List all calculated channels for the asset\n", "calc_channels = client.calculated_channels.list_(\n", " asset=asset.id_,\n", + " name=calc_channel_name,\n", " limit=10\n", ")\n", "\n", @@ -761,169 +1550,131 @@ " print(f\" Expression: {cc.expression}\")\n", " print(f\" Version: {cc.version}\")" ], - "id": "c3be1f869e83d59d" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Setting Rules\n", - "\n", - "Rules allow you to define conditions that trigger actions (like creating annotations) when met." - ], - "id": "f0e1d24d6fc507a2" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# Create a rule that monitors a channel or calculated channel\n", - "# This example creates a rule that triggers when a value exceeds a threshold\n", - "\n", - "if calc_channel:\n", - " rule_name = f\"high_{calc_channel.name}_alert\"\n", - "\n", - " # Check if rule already exists\n", - " existing_rule = client.rules.find(name=rule_name)\n", - "\n", - " if existing_rule:\n", - " print(f\"Rule '{rule_name}' already exists\")\n", - " rule = existing_rule\n", - " else:\n", - " print(f\"Creating rule: {rule_name}\")\n", - "\n", - " rule = client.rules.create(\n", - " RuleCreate(\n", - " name=rule_name,\n", - " description=f\"Alert when {calc_channel.name} exceeds threshold\",\n", - " expression=\"$1 > 10\", # Adjust threshold as needed\n", - " channel_references=[\n", - " ChannelReference(\n", - " channel_reference=\"$1\",\n", - " channel_identifier=calc_channel.name\n", - " ),\n", - " ],\n", - " action=RuleAction.annotation(\n", - " annotation_type=RuleAnnotationType.DATA_REVIEW,\n", - " tags=[\"high_value\", \"alert\"],\n", - " default_assignee_user_id=None,\n", - " ),\n", - " asset_ids=[asset.id_],\n", - " )\n", - " )\n", - "\n", - " print(f\"✓ Created rule: {rule.name}\")\n", - " print(f\" ID: {rule.id_}\")\n", - " print(f\" Expression: {rule.expression}\")\n", - " print(f\" Enabled: {rule.is_enabled}\")\n", - "elif channels:\n", - " # Create a rule using a regular channel\n", - " channel = channels[0]\n", - " rule_name = f\"high_{channel.name}_alert\"\n", - "\n", - " existing_rule = client.rules.find(name=rule_name)\n", - "\n", - " if existing_rule:\n", - " print(f\"Rule '{rule_name}' already exists\")\n", - " rule = existing_rule\n", - " else:\n", - " print(f\"Creating rule: {rule_name}\")\n", - "\n", - " rule = client.rules.create(\n", - " RuleCreate(\n", - " name=rule_name,\n", - " description=f\"Alert when {channel.name} exceeds threshold\",\n", - " expression=\"$1 > 100\", # Adjust threshold as needed\n", - " channel_references=[\n", - " ChannelReference(\n", - " channel_reference=\"$1\",\n", - " channel_identifier=channel.name\n", - " ),\n", - " ],\n", - " action=RuleAction.annotation(\n", - " annotation_type=RuleAnnotationType.DATA_REVIEW,\n", - " tags=[\"threshold_exceeded\"],\n", - " default_assignee_user_id=None,\n", - " ),\n", - " asset_ids=[asset.id_],\n", - " )\n", - " )\n", - "\n", - " print(f\"✓ Created rule: {rule.name}\")\n", - "else:\n", - " print(\"No channels available to create a rule\")\n", - " rule = None" - ], - "id": "cd85739f690f302d" - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": [ - "# List all rules for the asset\n", - "rules = client.rules.list_(\n", - " asset_ids=[asset.id_],\n", - " limit=10\n", - ")\n", - "\n", - "print(f\"Rules for asset '{asset.name}': {len(rules)}\")\n", - "for r in rules:\n", - " status = \"Enabled\" if r.is_enabled else \"Disabled\"\n", - " print(f\" - {r.name} ({status})\")\n", - " print(f\" Expression: {r.expression}\")\n", - " if r.action:\n", - " print(f\" Action: {r.action.action_type.name}\")" + "id": "c3be1f869e83d59d", + "outputs": [ + { + "data": { + "text/plain": [ + "Calculated channels for asset \u001B[32m'MarsRover0'\u001B[0m: \u001B[1;36m1\u001B[0m\n" + ], + "text/html": [ + "
Calculated channels for asset 'MarsRover0': 1\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " - is_even_per_voltage\n" + ], + "text/html": [ + "
  - is_even_per_voltage\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " Expression: $\u001B[1;36m1\u001B[0m \u001B[35m/\u001B[0m $\u001B[1;36m2\u001B[0m\n" + ], + "text/html": [ + "
    Expression: $1 / $2\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + " Version: \u001B[1;36m1\u001B[0m\n" + ], + "text/html": [ + "
    Version: 1\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } ], - "id": "3d53d29ebec3a241" - }, - { - "metadata": {}, - "cell_type": "markdown", - "source": [ - "## Summary\n", - "\n", - "This notebook demonstrated:\n", - "1. ✓ Initializing the Sift client with API credentials\n", - "2. ✓ Finding and filtering assets\n", - "3. ✓ Finding and filtering runs\n", - "4. ✓ Searching for channels by various criteria\n", - "5. ✓ Pulling time-series data as pandas DataFrames\n", - "6. ✓ Creating calculated channels with mathematical expressions\n", - "7. ✓ Setting up rules with conditions and actions\n", - "\n", - "### Next Steps\n", - "- Explore more filtering options for assets, runs, and channels\n", - "- Create more complex calculated channels with advanced expressions\n", - "- Set up rules with different action types (webhooks, etc.)\n", - "- Visualize the data using matplotlib or plotly\n", - "- Use the async API for better performance in production applications" - ], - "id": "ab250c26a5bfd825" + "execution_count": 25 }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-10-10T21:36:19.950884Z", + "start_time": "2025-10-10T21:36:19.888164Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ "# Optional: Clean up resources\n", "# Uncomment to archive the created calculated channel and rule\n", "\n", - "# if calc_channel:\n", - "# calc_channel.archive()\n", - "# print(f\"Archived calculated channel: {calc_channel.name}\")\n", - "\n", - "# if rule:\n", - "# rule.archive()\n", - "# print(f\"Archived rule: {rule.name}\")\n", + "if calc_channel:\n", + " calc_channel.archive()\n", + " print(f\"Archived calculated channel: {calc_channel.name}\")\n", "\n", "print(\"\\n✓ Example complete!\")" ], - "id": "37b76600aedba1a1" + "id": "37b76600aedba1a1", + "outputs": [ + { + "data": { + "text/plain": [ + "Archived calculated channel: is_even_per_voltage\n" + ], + "text/html": [ + "
Archived calculated channel: is_even_per_voltage\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + }, + { + "data": { + "text/plain": [ + "\n", + "✓ Example complete!\n" + ], + "text/html": [ + "
\n",
+       "✓ Example complete!\n",
+       "
\n" + ] + }, + "metadata": {}, + "output_type": "display_data", + "jetTransient": { + "display_id": null + } + } + ], + "execution_count": 26 } ], "metadata": { From 83ac86f85241ea5194269a4dcb19314d41ac86f7 Mon Sep 17 00:00:00 2001 From: Alex Luck Date: Fri, 10 Oct 2025 14:47:26 -0700 Subject: [PATCH 3/6] update docs --- python/docs/examples/basic.ipynb | 308 +++++++++++++------------------ python/mkdocs.yml | 4 +- 2 files changed, 129 insertions(+), 183 deletions(-) diff --git a/python/docs/examples/basic.ipynb b/python/docs/examples/basic.ipynb index 62215551d..268a5466e 100644 --- a/python/docs/examples/basic.ipynb +++ b/python/docs/examples/basic.ipynb @@ -9,12 +9,10 @@ "\n", "This notebook demonstrates the core features of the Sift Python client:\n", "- Initializing the Sift client\n", - "- Finding assets\n", - "- Finding runs\n", + "- Finding, creating, and updating resources\n", "- Searching channels\n", "- Pulling data\n", - "- Creating calculated channels\n", - "- Setting rules" + "- Creating calculated channels" ] }, { @@ -25,7 +23,7 @@ "\n", "This notebook is written in Jupyter Notebook format and can be run in any Jupyter environment.\n", "\n", - "Some additional package prerequisites are required to run this notebook:\n", + "Some additional package prerequisites are required to run this notebook\n", "- `notebook` for running Jupyter Notebooks\n", "- `python-dotenv` for loading environment variables\n", "- `rich` for pretty-printing output\n", @@ -51,8 +49,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:39.373921Z", - "start_time": "2025-10-10T21:24:38.917998Z" + "end_time": "2025-10-10T21:43:38.990325Z", + "start_time": "2025-10-10T21:43:38.928304Z" } }, "cell_type": "code", @@ -71,23 +69,14 @@ ")" ], "id": "497279d83878122e", - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/alexluck/Projects/sift-clients/python/lib/sift_client/resources/_base.py:9: SiftExperimentalWarning: `sift_client` is experimental and is subject to change. Use with caution.\n", - " _sift_client_experimental_warning()\n" - ] - } - ], - "execution_count": 1 + "outputs": [], + "execution_count": 41 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:39.448172Z", - "start_time": "2025-10-10T21:24:39.388721Z" + "end_time": "2025-10-10T21:43:39.071502Z", + "start_time": "2025-10-10T21:43:39.006349Z" } }, "cell_type": "code", @@ -125,7 +114,7 @@ } } ], - "execution_count": 2 + "execution_count": 42 }, { "metadata": {}, @@ -135,25 +124,27 @@ "\n", "Sift objects, such as Assets, Runs, etc. are all accessed via their API resources.\n", "\n", - "The [SiftClient](../../reference/sift_client/#sift_client.SiftClient) class provides these resources as properties:\n", - "- `assets`\n", - "- `runs`\n", - "- etc.\n", + "The [SiftClient](../../reference/sift_client/#sift_client.SiftClient) class provides these resources as properties\n", + "\n", + "* `assets`\n", + "* `runs`\n", + "* etc.\n", "\n", - "Asynchronous versions are also available by accessing the `async_` property of the client. For example:\n", - "- `client.async_.assets`\n", - "- `client.async_.runs`\n", - "- etc.\n", + "Asynchronous versions are also available by accessing the `async_` property of the client. For example\n", "\n", - "For example, the `Ping` resource can be used for a basic health check:" + "* `client.async_.assets`\n", + "* `client.async_.runs`\n", + "* etc.\n", + "\n", + "For example, the `Ping` resource can be used for a basic health check." ], "id": "378db56e29b1a355" }, { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:40.911413Z", - "start_time": "2025-10-10T21:24:39.459910Z" + "end_time": "2025-10-10T21:44:59.942480Z", + "start_time": "2025-10-10T21:44:59.885641Z" } }, "cell_type": "code", @@ -166,12 +157,12 @@ "'Hello from Sift!'" ] }, - "execution_count": 3, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 3 + "execution_count": 55 }, { "metadata": {}, @@ -187,15 +178,17 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "Resources generally offer similar interaction patterns and methods. For example, the `AssetsAPI` has:\n", - "- `get`\n", - "- `list_`\n", - "- `find`\n", - "- `update`\n", - "- `archive`\n", - "- `unarchive`\n", + "Resources generally offer similar interaction patterns and methods. For example, the `AssetsAPI` has\n", + "* `get`\n", + "* `list_`\n", + "* `find`\n", + "* `update`\n", + "* `archive`\n", + "* `unarchive`\n", + "\n", + "Other resources may offer additional methods such as `create`.\n", "\n", - "Other resources may offer additional methods such as `create`." + "These resource methods operate on and will return Sift object types. More on tehse can be found here: [sift_types](../../reference/sift_client/sift_types/)" ], "id": "894e74a9efdc603e" }, @@ -203,7 +196,7 @@ "metadata": {}, "cell_type": "markdown", "source": [ - "### Listing, Finding, and Getting\n", + "## Listing, Finding, and Getting\n", "\n", "`list_` can be used to retrieve objects that match a specific set of criteria:" ], @@ -212,8 +205,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:43.493121Z", - "start_time": "2025-10-10T21:24:43.390187Z" + "end_time": "2025-10-10T21:43:39.721956Z", + "start_time": "2025-10-10T21:43:39.665955Z" } }, "cell_type": "code", @@ -306,7 +299,7 @@ } } ], - "execution_count": 4 + "execution_count": 44 }, { "metadata": {}, @@ -317,8 +310,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:44.394852Z", - "start_time": "2025-10-10T21:24:44.336386Z" + "end_time": "2025-10-10T21:43:39.790539Z", + "start_time": "2025-10-10T21:43:39.732441Z" } }, "cell_type": "code", @@ -371,7 +364,7 @@ } } ], - "execution_count": 5 + "execution_count": 45 }, { "metadata": {}, @@ -382,8 +375,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:45.397172Z", - "start_time": "2025-10-10T21:24:45.336577Z" + "end_time": "2025-10-10T21:43:39.857266Z", + "start_time": "2025-10-10T21:43:39.798877Z" } }, "cell_type": "code", @@ -435,13 +428,13 @@ } } ], - "execution_count": 6 + "execution_count": 46 }, { "metadata": {}, "cell_type": "markdown", "source": [ - "### Creating, Updating, and Archiving\n", + "## Creating, Updating, and Archiving\n", "\n", "Most resources offer `create`, `update`, and `archive` methods.\n", "\n", @@ -452,8 +445,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:46.553174Z", - "start_time": "2025-10-10T21:24:46.502236Z" + "end_time": "2025-10-10T21:43:39.914350Z", + "start_time": "2025-10-10T21:43:39.860934Z" } }, "cell_type": "code", @@ -473,11 +466,11 @@ "data": { "text/plain": [ "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'21d845a4-2d70-45e6-b741-afce68878134'\u001B[0m,\n", + " \u001B[33mid_\u001B[0m=\u001B[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001B[0m,\n", " \u001B[33mname\u001B[0m=\u001B[32m'Test Run'\u001B[0m,\n", " \u001B[33mdescription\u001B[0m=\u001B[32m'A test run'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m508353\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m510091\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m913134\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m915093\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", @@ -486,21 +479,21 @@ " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m502969\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", + " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m861550\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m8602\u001B[0m\u001B[1m)\u001B[0m,\n", - " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'74213648-793f-4023-a4c8-ba3f81af94c1'\u001B[0m,\n", + " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m54929\u001B[0m\u001B[1m)\u001B[0m,\n", + " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001B[0m,\n", " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m\n", "\u001B[1m)\u001B[0m\n" ], "text/html": [ "
Run(\n",
-       "    id_='21d845a4-2d70-45e6-b741-afce68878134',\n",
+       "    id_='523c6f2a-181c-4ee7-8876-421901daf97f',\n",
        "    name='Test Run',\n",
        "    description='A test run',\n",
-       "    created_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 508353, tzinfo=datetime.timezone.utc),\n",
-       "    modified_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 510091, tzinfo=datetime.timezone.utc),\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 43, 39, 913134, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 43, 39, 915093, tzinfo=datetime.timezone.utc),\n",
        "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
        "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
        "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
@@ -509,10 +502,10 @@
        "    asset_ids=[],\n",
        "    is_adhoc=False,\n",
        "    is_archived=False,\n",
-       "    start_time=datetime.datetime(2025, 10, 10, 14, 24, 46, 502969, tzinfo=datetime.timezone.utc),\n",
+       "    start_time=datetime.datetime(2025, 10, 10, 14, 43, 39, 861550, tzinfo=datetime.timezone.utc),\n",
        "    stop_time=None,\n",
-       "    duration=datetime.timedelta(seconds=25200, microseconds=8602),\n",
-       "    default_report_id='74213648-793f-4023-a4c8-ba3f81af94c1',\n",
+       "    duration=datetime.timedelta(seconds=25200, microseconds=54929),\n",
+       "    default_report_id='854787b6-4e38-4c81-bdf0-8d143c791d01',\n",
        "    client_key=None,\n",
        "    archived_date=None\n",
        ")\n",
@@ -526,13 +519,13 @@
      }
     }
    ],
-   "execution_count": 7
+   "execution_count": 47
   },
   {
    "metadata": {
     "ExecuteTime": {
-     "end_time": "2025-10-10T21:24:47.415518Z",
-     "start_time": "2025-10-10T21:24:47.357814Z"
+     "end_time": "2025-10-10T21:43:39.983767Z",
+     "start_time": "2025-10-10T21:43:39.922700Z"
     }
    },
    "cell_type": "code",
@@ -550,11 +543,11 @@
      "data": {
       "text/plain": [
        "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n",
-       "    \u001B[33mid_\u001B[0m=\u001B[32m'21d845a4-2d70-45e6-b741-afce68878134'\u001B[0m,\n",
+       "    \u001B[33mid_\u001B[0m=\u001B[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001B[0m,\n",
        "    \u001B[33mname\u001B[0m=\u001B[32m'Updated Test Run'\u001B[0m,\n",
        "    \u001B[33mdescription\u001B[0m=\u001B[32m'An updated test run'\u001B[0m,\n",
-       "    \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m508353\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
-       "    \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m47\u001B[0m, \u001B[1;36m369552\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m913134\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m981793\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
        "    \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n",
        "    \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n",
        "    \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n",
@@ -563,21 +556,21 @@
        "    \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n",
        "    \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n",
        "    \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n",
-       "    \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m502969\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m861550\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
        "    \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n",
-       "    \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m870395\u001B[0m\u001B[1m)\u001B[0m,\n",
-       "    \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'74213648-793f-4023-a4c8-ba3f81af94c1'\u001B[0m,\n",
+       "    \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m123957\u001B[0m\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001B[0m,\n",
        "    \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n",
        "    \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m\n",
        "\u001B[1m)\u001B[0m\n"
       ],
       "text/html": [
        "
Run(\n",
-       "    id_='21d845a4-2d70-45e6-b741-afce68878134',\n",
+       "    id_='523c6f2a-181c-4ee7-8876-421901daf97f',\n",
        "    name='Updated Test Run',\n",
        "    description='An updated test run',\n",
-       "    created_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 508353, tzinfo=datetime.timezone.utc),\n",
-       "    modified_date=datetime.datetime(2025, 10, 10, 21, 24, 47, 369552, tzinfo=datetime.timezone.utc),\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 43, 39, 913134, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 43, 39, 981793, tzinfo=datetime.timezone.utc),\n",
        "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
        "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
        "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
@@ -586,10 +579,10 @@
        "    asset_ids=[],\n",
        "    is_adhoc=False,\n",
        "    is_archived=False,\n",
-       "    start_time=datetime.datetime(2025, 10, 10, 14, 24, 46, 502969, tzinfo=datetime.timezone.utc),\n",
+       "    start_time=datetime.datetime(2025, 10, 10, 14, 43, 39, 861550, tzinfo=datetime.timezone.utc),\n",
        "    stop_time=None,\n",
-       "    duration=datetime.timedelta(seconds=25200, microseconds=870395),\n",
-       "    default_report_id='74213648-793f-4023-a4c8-ba3f81af94c1',\n",
+       "    duration=datetime.timedelta(seconds=25200, microseconds=123957),\n",
+       "    default_report_id='854787b6-4e38-4c81-bdf0-8d143c791d01',\n",
        "    client_key=None,\n",
        "    archived_date=None\n",
        ")\n",
@@ -603,13 +596,13 @@
      }
     }
    ],
-   "execution_count": 8
+   "execution_count": 48
   },
   {
    "metadata": {
     "ExecuteTime": {
-     "end_time": "2025-10-10T21:24:48.150939Z",
-     "start_time": "2025-10-10T21:24:48.085422Z"
+     "end_time": "2025-10-10T21:43:40.057415Z",
+     "start_time": "2025-10-10T21:43:39.988773Z"
     }
    },
    "cell_type": "code",
@@ -624,11 +617,11 @@
      "data": {
       "text/plain": [
        "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n",
-       "    \u001B[33mid_\u001B[0m=\u001B[32m'21d845a4-2d70-45e6-b741-afce68878134'\u001B[0m,\n",
+       "    \u001B[33mid_\u001B[0m=\u001B[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001B[0m,\n",
        "    \u001B[33mname\u001B[0m=\u001B[32m'Updated Test Run'\u001B[0m,\n",
        "    \u001B[33mdescription\u001B[0m=\u001B[32m'An updated test run'\u001B[0m,\n",
-       "    \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m508353\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
-       "    \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m48\u001B[0m, \u001B[1;36m102385\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m913134\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m40\u001B[0m, \u001B[1;36m52001\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
        "    \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n",
        "    \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n",
        "    \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n",
@@ -637,21 +630,21 @@
        "    \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n",
        "    \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n",
        "    \u001B[33mis_archived\u001B[0m=\u001B[3;92mTrue\u001B[0m,\n",
-       "    \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m46\u001B[0m, \u001B[1;36m502969\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m861550\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n",
        "    \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n",
-       "    \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25201\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m605088\u001B[0m\u001B[1m)\u001B[0m,\n",
-       "    \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'74213648-793f-4023-a4c8-ba3f81af94c1'\u001B[0m,\n",
+       "    \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m196350\u001B[0m\u001B[1m)\u001B[0m,\n",
+       "    \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001B[0m,\n",
        "    \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n",
-       "    \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m24\u001B[0m, \u001B[1;36m48\u001B[0m, \u001B[1;36m98579\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n",
+       "    \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m40\u001B[0m, \u001B[1;36m48186\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n",
        "\u001B[1m)\u001B[0m\n"
       ],
       "text/html": [
        "
Run(\n",
-       "    id_='21d845a4-2d70-45e6-b741-afce68878134',\n",
+       "    id_='523c6f2a-181c-4ee7-8876-421901daf97f',\n",
        "    name='Updated Test Run',\n",
        "    description='An updated test run',\n",
-       "    created_date=datetime.datetime(2025, 10, 10, 21, 24, 46, 508353, tzinfo=datetime.timezone.utc),\n",
-       "    modified_date=datetime.datetime(2025, 10, 10, 21, 24, 48, 102385, tzinfo=datetime.timezone.utc),\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 43, 39, 913134, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 43, 40, 52001, tzinfo=datetime.timezone.utc),\n",
        "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
        "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
        "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
@@ -660,12 +653,12 @@
        "    asset_ids=[],\n",
        "    is_adhoc=False,\n",
        "    is_archived=True,\n",
-       "    start_time=datetime.datetime(2025, 10, 10, 14, 24, 46, 502969, tzinfo=datetime.timezone.utc),\n",
+       "    start_time=datetime.datetime(2025, 10, 10, 14, 43, 39, 861550, tzinfo=datetime.timezone.utc),\n",
        "    stop_time=None,\n",
-       "    duration=datetime.timedelta(seconds=25201, microseconds=605088),\n",
-       "    default_report_id='74213648-793f-4023-a4c8-ba3f81af94c1',\n",
+       "    duration=datetime.timedelta(seconds=25200, microseconds=196350),\n",
+       "    default_report_id='854787b6-4e38-4c81-bdf0-8d143c791d01',\n",
        "    client_key=None,\n",
-       "    archived_date=datetime.datetime(2025, 10, 10, 21, 24, 48, 98579, tzinfo=datetime.timezone.utc)\n",
+       "    archived_date=datetime.datetime(2025, 10, 10, 21, 43, 40, 48186, tzinfo=datetime.timezone.utc)\n",
        ")\n",
        "
\n" ] @@ -677,7 +670,7 @@ } } ], - "execution_count": 9 + "execution_count": 49 }, { "metadata": {}, @@ -692,8 +685,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:49.389722Z", - "start_time": "2025-10-10T21:24:49.255833Z" + "end_time": "2025-10-10T21:43:40.313373Z", + "start_time": "2025-10-10T21:43:40.062560Z" } }, "cell_type": "code", @@ -951,13 +944,13 @@ } } ], - "execution_count": 10 + "execution_count": 50 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:50.361561Z", - "start_time": "2025-10-10T21:24:50.299511Z" + "end_time": "2025-10-10T21:43:40.414219Z", + "start_time": "2025-10-10T21:43:40.325320Z" } }, "cell_type": "code", @@ -1035,13 +1028,13 @@ } } ], - "execution_count": 11 + "execution_count": 51 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:24:51.506365Z", - "start_time": "2025-10-10T21:24:51.460199Z" + "end_time": "2025-10-10T21:43:40.482064Z", + "start_time": "2025-10-10T21:43:40.429852Z" } }, "cell_type": "code", @@ -1075,7 +1068,7 @@ } } ], - "execution_count": 12 + "execution_count": 52 }, { "metadata": {}, @@ -1090,8 +1083,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:31:53.467442Z", - "start_time": "2025-10-10T21:31:52.933530Z" + "end_time": "2025-10-10T21:43:40.980438Z", + "start_time": "2025-10-10T21:43:40.491510Z" } }, "cell_type": "code", @@ -1376,7 +1369,7 @@ } } ], - "execution_count": 21 + "execution_count": 53 }, { "metadata": {}, @@ -1391,8 +1384,8 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:34:03.552648Z", - "start_time": "2025-10-10T21:34:03.416644Z" + "end_time": "2025-10-10T21:43:41.254295Z", + "start_time": "2025-10-10T21:43:41.100146Z" } }, "cell_type": "code", @@ -1460,78 +1453,31 @@ } }, { - "data": { - "text/plain": [ - "\u001B[1;35mCalculatedChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'd283b5fe-fed5-4260-93d1-8bd65bec4bfe'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'is_even_per_voltage'\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'Ratio of is_even to voltage'\u001B[0m,\n", - " \u001B[33mexpression\u001B[0m=\u001B[32m'$1 / $2'\u001B[0m,\n", - " \u001B[33mchannel_references\u001B[0m=\u001B[1m[\u001B[0m\n", - " \u001B[1m{\u001B[0m\u001B[32m'channel_reference'\u001B[0m: \u001B[32m'$1'\u001B[0m, \u001B[32m'channel_identifier'\u001B[0m: \u001B[32m'is_even'\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[1m{\u001B[0m\u001B[32m'channel_reference'\u001B[0m: \u001B[32m'$2'\u001B[0m, \u001B[32m'channel_identifier'\u001B[0m: \u001B[32m'voltage'\u001B[0m\u001B[1m}\u001B[0m\n", - " \u001B[1m]\u001B[0m,\n", - " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33munits\u001B[0m=\u001B[32m''\u001B[0m,\n", - " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mtag_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mall_assets\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", - " \u001B[33mclient_key\u001B[0m=\u001B[32m''\u001B[0m,\n", - " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33mversion_id\u001B[0m=\u001B[32m'0923ec64-9799-4e73-8038-71496227a846'\u001B[0m,\n", - " \u001B[33mversion\u001B[0m=\u001B[1;36m1\u001B[0m,\n", - " \u001B[33mchange_message\u001B[0m=\u001B[32m'Created calculated channel'\u001B[0m,\n", - " \u001B[33muser_notes\u001B[0m=\u001B[32m''\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m34\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m533939\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m34\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m533939\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], - "text/html": [ - "
CalculatedChannel(\n",
-       "    id_='d283b5fe-fed5-4260-93d1-8bd65bec4bfe',\n",
-       "    name='is_even_per_voltage',\n",
-       "    description='Ratio of is_even to voltage',\n",
-       "    expression='$1 / $2',\n",
-       "    channel_references=[\n",
-       "        {'channel_reference': '$1', 'channel_identifier': 'is_even'},\n",
-       "        {'channel_reference': '$2', 'channel_identifier': 'voltage'}\n",
-       "    ],\n",
-       "    is_archived=False,\n",
-       "    units='',\n",
-       "    asset_ids=['61d6e4f0-8287-4678-b071-18a95fcd9db6'],\n",
-       "    tag_ids=[],\n",
-       "    all_assets=False,\n",
-       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
-       "    client_key='',\n",
-       "    archived_date=None,\n",
-       "    version_id='0923ec64-9799-4e73-8038-71496227a846',\n",
-       "    version=1,\n",
-       "    change_message='Created calculated channel',\n",
-       "    user_notes='',\n",
-       "    created_date=datetime.datetime(2025, 10, 10, 21, 34, 3, 533939, tzinfo=datetime.timezone.utc),\n",
-       "    modified_date=datetime.datetime(2025, 10, 10, 21, 34, 3, 533939, tzinfo=datetime.timezone.utc),\n",
-       "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
-       "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c'\n",
-       ")\n",
-       "
\n" - ] - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } + "ename": "AioRpcError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mAioRpcError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[54], line 24\u001B[0m\n\u001B[1;32m 21\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 22\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCreating calculated channel: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mcalc_channel_name\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m---> 24\u001B[0m calc_channel \u001B[38;5;241m=\u001B[39m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcalculated_channels\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcreate\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 25\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mdict\u001B[39;49m\u001B[43m(\u001B[49m\n\u001B[1;32m 26\u001B[0m \u001B[43m \u001B[49m\u001B[43mname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcalc_channel_name\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 27\u001B[0m \u001B[43m \u001B[49m\u001B[43mdescription\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43mf\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mRatio of \u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mchannel1\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m to \u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mchannel2\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 28\u001B[0m \u001B[43m \u001B[49m\u001B[43mexpression\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m$1 / $2\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# $1 and $2 refer to the channel references below\u001B[39;49;00m\n\u001B[1;32m 29\u001B[0m \u001B[43m \u001B[49m\u001B[43mexpression_channel_references\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\n\u001B[1;32m 30\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mdict\u001B[39;49m\u001B[43m(\u001B[49m\n\u001B[1;32m 31\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_reference\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m$1\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 32\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_identifier\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchannel1\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\n\u001B[1;32m 33\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 34\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mdict\u001B[39;49m\u001B[43m(\u001B[49m\n\u001B[1;32m 35\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_reference\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m$2\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 36\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_identifier\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchannel2\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\n\u001B[1;32m 37\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 38\u001B[0m \u001B[43m \u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 39\u001B[0m \u001B[43m \u001B[49m\u001B[43masset_ids\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43masset\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mid_\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 40\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 41\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 43\u001B[0m \u001B[38;5;28mprint\u001B[39m(calc_channel)\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:72\u001B[0m, in \u001B[0;36mgenerate_sync_api.._make_sync..sync_func\u001B[0;34m(self, *a, **kw)\u001B[0m\n\u001B[1;32m 70\u001B[0m \u001B[38;5;129m@wraps\u001B[39m(async_func)\n\u001B[1;32m 71\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21msync_func\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39ma, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkw):\n\u001B[0;32m---> 72\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_run\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mgetattr\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_async_impl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfunc_name\u001B[49m\u001B[43m)\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43ma\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkw\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:56\u001B[0m, in \u001B[0;36mgenerate_sync_api.._run\u001B[0;34m(self, coro)\u001B[0m\n\u001B[1;32m 54\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_run\u001B[39m(\u001B[38;5;28mself\u001B[39m, coro):\n\u001B[1;32m 55\u001B[0m loop \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_async_impl\u001B[38;5;241m.\u001B[39mclient\u001B[38;5;241m.\u001B[39mget_asyncio_loop()\n\u001B[0;32m---> 56\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43masyncio\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrun_coroutine_threadsafe\u001B[49m\u001B[43m(\u001B[49m\u001B[43mcoro\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mloop\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mresult\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:444\u001B[0m, in \u001B[0;36mFuture.result\u001B[0;34m(self, timeout)\u001B[0m\n\u001B[1;32m 442\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m CancelledError()\n\u001B[1;32m 443\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_state \u001B[38;5;241m==\u001B[39m FINISHED:\n\u001B[0;32m--> 444\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__get_result\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 445\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 446\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTimeoutError\u001B[39;00m()\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:389\u001B[0m, in \u001B[0;36mFuture.__get_result\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 387\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception:\n\u001B[1;32m 388\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 389\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception\n\u001B[1;32m 390\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n\u001B[1;32m 391\u001B[0m \u001B[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001B[39;00m\n\u001B[1;32m 392\u001B[0m \u001B[38;5;28mself\u001B[39m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/resources/calculated_channels.py:208\u001B[0m, in \u001B[0;36mCalculatedChannelsAPIAsync.create\u001B[0;34m(self, create)\u001B[0m\n\u001B[1;32m 205\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(create, \u001B[38;5;28mdict\u001B[39m):\n\u001B[1;32m 206\u001B[0m create \u001B[38;5;241m=\u001B[39m CalculatedChannelCreate\u001B[38;5;241m.\u001B[39mmodel_validate(create)\n\u001B[0;32m--> 208\u001B[0m created_calc_channel, _ \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_low_level_client\u001B[38;5;241m.\u001B[39mcreate_calculated_channel(\n\u001B[1;32m 209\u001B[0m create\u001B[38;5;241m=\u001B[39mcreate\n\u001B[1;32m 210\u001B[0m )\n\u001B[1;32m 211\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_apply_client_to_instance(created_calc_channel)\n", + "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/calculated_channels.py:78\u001B[0m, in \u001B[0;36mCalculatedChannelsLowLevelClient.create_calculated_channel\u001B[0;34m(self, create)\u001B[0m\n\u001B[1;32m 74\u001B[0m \u001B[38;5;28;01masync\u001B[39;00m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mcreate_calculated_channel\u001B[39m(\n\u001B[1;32m 75\u001B[0m \u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39m, create: CalculatedChannelCreate\n\u001B[1;32m 76\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mtuple\u001B[39m[CalculatedChannel, \u001B[38;5;28mlist\u001B[39m[Any]]:\n\u001B[1;32m 77\u001B[0m request \u001B[38;5;241m=\u001B[39m create\u001B[38;5;241m.\u001B[39mto_proto()\n\u001B[0;32m---> 78\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grpc_client\u001B[38;5;241m.\u001B[39mget_stub(\n\u001B[1;32m 79\u001B[0m CalculatedChannelServiceStub\n\u001B[1;32m 80\u001B[0m )\u001B[38;5;241m.\u001B[39mCreateCalculatedChannel(request)\n\u001B[1;32m 81\u001B[0m response \u001B[38;5;241m=\u001B[39m cast(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCreateCalculatedChannelResponse\u001B[39m\u001B[38;5;124m\"\u001B[39m, response)\n\u001B[1;32m 83\u001B[0m calculated_channel \u001B[38;5;241m=\u001B[39m CalculatedChannel\u001B[38;5;241m.\u001B[39m_from_proto(response\u001B[38;5;241m.\u001B[39mcalculated_channel)\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_interceptor.py:472\u001B[0m, in \u001B[0;36m_InterceptedUnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 470\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__await__\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[1;32m 471\u001B[0m call \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_interceptors_task\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[0;32m--> 472\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m call\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[1;32m 473\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", + "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_call.py:327\u001B[0m, in \u001B[0;36m_UnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 325\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m asyncio\u001B[38;5;241m.\u001B[39mCancelledError()\n\u001B[1;32m 326\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 327\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m _create_rpc_error(\n\u001B[1;32m 328\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_initial_metadata,\n\u001B[1;32m 329\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_status,\n\u001B[1;32m 330\u001B[0m )\n\u001B[1;32m 331\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 332\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", + "\u001B[0;31mAioRpcError\u001B[0m: " + ] } ], - "execution_count": 23 + "execution_count": 54 }, { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:35:07.418677Z", + "end_time": "2025-10-10T21:43:41.257980Z", "start_time": "2025-10-10T21:35:07.170355Z" } }, @@ -1622,7 +1568,7 @@ { "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:36:19.950884Z", + "end_time": "2025-10-10T21:43:41.258564Z", "start_time": "2025-10-10T21:36:19.888164Z" } }, diff --git a/python/mkdocs.yml b/python/mkdocs.yml index 7e520bae6..f4098b10a 100644 --- a/python/mkdocs.yml +++ b/python/mkdocs.yml @@ -53,10 +53,10 @@ extra: nav: - Home: index.md - - Examples: - - examples/basic.ipynb - Sift Py API - Sift Client API (New) + - Examples: + - examples/basic.ipynb # - Guides: # - Logging # - Error Handling From 5923a4ed792eb4410fcaeb7155841427adf01af2 Mon Sep 17 00:00:00 2001 From: Alex Luck Date: Fri, 10 Oct 2025 14:58:08 -0700 Subject: [PATCH 4/6] update docs --- python/lib/sift_client/__init__.py | 221 ++++++------------ python/lib/sift_client/examples/__init__.py | 0 .../examples/generic_workflow_example.py | 127 ---------- python/lib/sift_client/resources/__init__.py | 152 ++++++++++++ 4 files changed, 229 insertions(+), 271 deletions(-) delete mode 100644 python/lib/sift_client/examples/__init__.py delete mode 100644 python/lib/sift_client/examples/generic_workflow_example.py diff --git a/python/lib/sift_client/__init__.py b/python/lib/sift_client/__init__.py index 5bcf1f5c3..d724932fd 100644 --- a/python/lib/sift_client/__init__.py +++ b/python/lib/sift_client/__init__.py @@ -1,11 +1,17 @@ -"""!!! warning +"""Sift Client Library - Python client for interacting with Sift APIs. + +!!! warning The Sift Client is experimental and is subject to change. +## Overview -# Sift Client Library +This library provides a high-level Python client for interacting with Sift APIs. It offers: -This library provides a high-level Python client for interacting with Sift APIs. It offers both synchronous and -asynchronous interfaces, strong type checking, and a Pythonic API design. +- **Synchronous and asynchronous interfaces** for all operations +- **Strong type checking** with Pydantic models +- **Pythonic API design** with intuitive method names +- **Comprehensive filtering** capabilities for queries +- **Automatic type conversion** between protobuf and Python types ## Installation @@ -13,193 +19,120 @@ pip install sift-stack-py ``` -## Getting Started - -### Initializing the Client +## Quick Start -You can initialize the Sift client with your API key and service URLs: +### Initialize the Client ```python from sift_client import SiftClient -from datetime import datetime -# Initialize with individual parameters +# Initialize with credentials client = SiftClient( api_key="your-api-key", - grpc_url="your-sift-grpc-url", - rest_url="your-sift-rest-url" -) - -# Or use a connection configuration -from sift_client.transport import SiftConnectionConfig - -config = SiftConnectionConfig( - api_key="your-api-key", - grpc_url="your-sift-grpc-url", - rest_url="your-sift-rest-url" + grpc_url="grpc.siftstack.com:443", + rest_url="https://api.siftstack.com" ) -client = SiftClient(connection_config=config) ``` -The `SiftConnectionConfig` provides access to additional configuration options such as `use_ssl` and `cert_via_openssl`. - -### Using Synchronous and Asynchronous APIs - -The Sift client provides both synchronous and asynchronous versions of all APIs. You can choose the one that best fits -your application's needs. - -#### Synchronous API - -The synchronous API is perfect for scripts, notebooks, and applications that don't need asynchronous operation: +### Basic Operations ```python -# Get an asset by ID +# Get an asset asset = client.assets.get(asset_id="asset123") -# List assets with filtering -assets = client.assets.list_( - name_contains="example", - created_after=datetime(2023, 1, 1), - include_archived=False +# List resources with filtering +runs = client.runs.list_( + assets=[asset.id_], + start_time_after=datetime.now() - timedelta(days=7), + limit=10 ) -# Find a single asset matching criteria -asset = client.assets.find(name="my-asset") -``` +# Update a resource +asset.update({"tags": ["production", "v2"]}) -#### Asynchronous API +# Create a new resource +run = client.runs.create({ + "name": "Test Run", + "asset_ids": [asset.id_], + "start_time": datetime.now() +}) +``` -The asynchronous API is ideal for high-performance applications and services that need to make concurrent API calls: +### Async Usage ```python import asyncio +async def main(): + # Use async_ accessor for async operations + asset = await client.async_.assets.get(asset_id="asset123") + runs = await client.async_.runs.list_(limit=10) + return asset, runs -async def get_asset_async(): - # Get an asset by ID asynchronously - asset = await client.assets_async.get(asset_id="asset123") - - # Running Sync within async also works - some_other_asset = client.assets.get(asset_id="asset456") - - return asset - - -# Run in an async context -asset = asyncio.run(get_asset_async()) - -``` - -### Working with Sift Types - -Sift types (like `Asset`, `Run`, etc.) are immutable Pydantic models that provide a convenient interface for working -with Sift resources. - -#### Accessing Properties - -```python -# Get an asset -asset = client.assets.get(asset_id="asset123") - -# Access properties -print(f"Asset name: {asset.name}") -print(f"Created on: {asset.created_date}") -print(f"Tags: {', '.join(asset.tags)}") -print(f"Is archived: {asset.is_archived}") +result = asyncio.run(main()) ``` -#### Using Methods on Sift Types +## Key Components -Sift types have convenient methods for common operations. These methods use the synchronous API internally. -**Using these methods will update the instance in-place.** +### Resources -```python -# Get an asset -asset = client.assets.get(asset_id="asset123") +Resource APIs provide methods for interacting with Sift services. Each resource supports +operations like `get()`, `list_()`, `create()`, `update()`, and `archive()`. -# Archive the asset -asset.archive(archive_runs=True) +**Available Resources:** -# Update the asset -asset.update({ - "tags": ["updated", "example"] -}) -``` +- `client.assets` - Manage physical or logical entities +- `client.runs` - Manage time-bounded operational periods +- etc. -> **Note:** Type methods only work with the synchronous API. If you need to use the asynchronous API, you should use the -> resource APIs directly. +See [resources](resources/) for detailed documentation and a complete list. -#### Creating Update Models +### Types -For more complex updates, you can create update models (instead of a key-value dictionary): +Sift types are immutable Pydantic models representing Sift objects. They provide +type-safe access to properties and convenience methods for common operations. -```python -from sift_client.types.asset import AssetUpdate +**Available Types:** -# Create an update model -update = AssetUpdate(tags=["new", "tags"]) +- `Asset`, `AssetUpdate` - Asset resources +- `Run`, `RunCreate`, `RunUpdate` - Run resources +- etc. -# Apply the update -asset = client.assets.update(asset="asset123", update=update) +See [sift_types](sift_types/) for detailed documentation and a complete list. -# Or using the asset method -asset = client.assets.get(asset_id="asset123").update(update) -``` +## Examples -## Advanced Usage +For complete examples, see the [examples](../examples/) directory. -### Working with Tags +## Connection Configuration -Tags are a powerful way to organize and filter your assets: +For advanced connection options: ```python -# Add tags when updating an asset -asset.update({ - "tags": ["production", "model-v1", "trained"] -}) +from sift_client.transport import SiftConnectionConfig, GrpcConfig, RestConfig -# Filter assets by tags -production_assets = client.assets.list_( - tags=["production"] -) -``` - -### Filtering Assets - -The client provides various ways to filter different Sift types: - -```python -# Filter by name (exact match) -assets = client.assets.list_(name="my-model") - -# Filter by name (contains) -assets = client.assets.list_(name_contains="model") - -# Filter by name (regex) -assets = client.assets.list_(name_regex="model-v[0-9]+") - -# Filter by creation date -assets = client.assets.list_( - created_after=datetime(2023, 1, 1), - created_before=datetime(2023, 12, 31) -) - -# Filter by modification date -assets = client.assets.list_( - modified_after=datetime(2023, 6, 1) +config = SiftConnectionConfig( + grpc_config=GrpcConfig( + uri="grpc.siftstack.com:443", + api_key="your-api-key", + use_ssl=True + ), + rest_config=RestConfig( + uri="https://api.siftstack.com", + api_key="your-api-key" + ) ) -# Include archived assets -all_assets = client.assets.list_(include_archived=True) - -# Limit the number of results -recent_assets = client.assets.list_( - limit=10, - order_by="modified_date desc" -) +client = SiftClient(connection_config=config) ``` +## Best Practices +1. **Use sync APIs** for notebooks, scripts, and simple applications +2. **Use async APIs** for high-performance services with concurrent operations +3. **Leverage filtering** to reduce data transfer and improve performance +4. **Reuse client instances** rather than creating new ones for each operation +5. **Use type hints** to get full IDE support and catch errors early """ import logging diff --git a/python/lib/sift_client/examples/__init__.py b/python/lib/sift_client/examples/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/python/lib/sift_client/examples/generic_workflow_example.py b/python/lib/sift_client/examples/generic_workflow_example.py deleted file mode 100644 index 1263928ad..000000000 --- a/python/lib/sift_client/examples/generic_workflow_example.py +++ /dev/null @@ -1,127 +0,0 @@ -# import asyncio -# import os -# from datetime import datetime, timezone -# -# from sift_client.client import SiftClient -# -# # Import sift_client types for calculated channels and rules -# from sift_client.sift_types import ( -# CalculatedChannelUpdate, -# ChannelReference, -# RuleAction, -# RuleAnnotationType, -# RuleCreate, -# RuleUpdate, -# ) -# -# """ -# Placeholder for future examples. FD-67 -# """ -# -# -# async def main(): -# grpc_url = os.getenv("SIFT_GRPC_URI", "localhost:50051") -# api_key = os.getenv("SIFT_API_KEY", "") -# rest_url = os.getenv("SIFT_REST_URI", "localhost:8080") -# client = SiftClient(grpc_url=grpc_url, api_key=api_key, rest_url=rest_url) -# -# asset = client.assets.find(name="NostromoLV426") -# asset_id = asset.id_ -# print("Found asset", asset.name) -# -# calculated_channels = client.calculated_channels.list_( -# name_regex="velocity_per.*", -# asset_id=asset_id, -# ) -# updated = False -# calculated_channel = None -# if calculated_channels: -# print(f"Found calculated channels: {[cc.name for cc in calculated_channels]}") -# for cc in calculated_channels: -# if cc.name == "velocity_per_voltage": -# calculated_channel = cc.update( -# CalculatedChannelUpdate( -# expression="$1 / $2 + 0.1", -# expression_channel_references=cc.channel_references, -# ) -# ) -# print("Updated calculated channel", calculated_channel) -# else: -# # Create a calculated channel that divides mainmotor.velocity by voltage -# print("\nCreating calculated channel...") -# calculated_channel = client.calculated_channels.create( -# dict( -# name="velocity_per_voltage", -# description="Ratio of mainmotor velocity to voltage", -# expression="$1 / $2", # $1 = mainmotor.velocity, $2 = voltage -# channel_references=[ -# ChannelReference( -# channel_reference="$1", channel_identifier="mainmotor.velocity" -# ), -# ChannelReference(channel_reference="$2", channel_identifier="voltage"), -# ], -# units="velocity/voltage", -# asset_ids=[asset_id], -# user_notes="Created to monitor velocity-to-voltage ratio", -# ) -# ) -# print( -# f"Created calculated channel: {calculated_channel.name} (ID: {calculated_channel.calculated_channel_id})" -# ) -# -# # Create a rule that creates an annotation when the ratio is above 0.1 -# rule_search = "high_velocity_voltage" -# print(f"Looking for rule containing {rule_search}") -# rules = client.rules.list( -# name_contains=rule_search, -# ) -# if rules: -# print(f"Found rules: {[rule.name for rule in rules]}") -# # Example of batch get if you just had the rule ids: -# rules = client.rules.batch_get(rule_ids=[rule.rule_id for rule in rules]) -# print(f"Batch get on IDs also works: {[rule.name for rule in rules]}") -# -# rule = rules[0] -# print(f"Updating rule: {rule.name}") -# rule = rule.update( -# RuleUpdate( -# description=f"Alert when velocity-to-voltage ratio exceeds 0.1 (Updated at {datetime.now(tz=timezone.utc).isoformat()})", -# asset_ids=[asset_id], -# ) -# ) -# updated = True -# else: -# print(f"No rules found for {rule_search}") -# rules = client.rules.list_( -# asset_ids=[asset_id], -# ) -# if rules: -# print(f"However these rules do exist: {[rule.name for rule in rules]}") -# print("Attempting to create rule for high_velocity_voltage_ratio_alert") -# rule = client.rules.create( -# RuleCreate( -# name="high_velocity_voltage_ratio_alert", -# description="Alert when velocity-to-voltage ratio exceeds 0.1", -# expression="$1 > 0.1", -# channel_references=[ -# ChannelReference( -# channel_reference="$1", -# channel_identifier=calculated_channel.name, -# ), -# ], -# action=RuleAction.annotation( -# annotation_type=RuleAnnotationType.DATA_REVIEW, -# tags=["high_ratio", "alert"], -# default_assignee_user_id=None, # You can set a user ID here if needed -# ), -# ) -# ) -# print(f"Created rule: {rule.name} (ID: {rule.rule_id})") -# -# if updated: -# print("Second run through, deleting rule") -# rule.delete() -# -# -# if __name__ == "__main__": -# asyncio.run(main()) diff --git a/python/lib/sift_client/resources/__init__.py b/python/lib/sift_client/resources/__init__.py index 5997acb02..e4b7e2747 100644 --- a/python/lib/sift_client/resources/__init__.py +++ b/python/lib/sift_client/resources/__init__.py @@ -1,3 +1,155 @@ +"""Sift Resources - API interfaces for interacting with Sift services. + +This module provides high-level API interfaces for interacting with Sift resources. +Each resource API provides methods for common operations like listing, getting, creating, +updating, and archiving resources. + +## Overview + +Resource APIs are the primary way to interact with Sift services. They provide: + +- **Type-safe methods** with full IDE autocomplete support +- **Automatic type conversion** between protobuf and Python types +- **Flexible filtering** using CEL (Common Expression Language) queries +- **Both sync and async** versions of most APIs +- **Consistent interface** across all resource types + +## Synchronous vs Asynchronous APIs + +All resource APIs are available in both synchronous and asynchronous versions: + +- **Synchronous APIs** (e.g., `AssetsAPI`) - Ideal for scripts, notebooks, and simple applications +- **Asynchronous APIs** (e.g., `AssetsAPIAsync`) - Ideal for high-performance applications with concurrent operations + +### Example Usage + +```python +from sift_client import SiftClient + +client = SiftClient(api_key="...", grpc_url="...", rest_url="...") + +# Synchronous API usage +asset = client.assets.get(asset_id="asset123") +runs = client.runs.list_(assets=[asset.id_], limit=10) + +# Asynchronous API usage +async def get_data(): + asset = await client.async_.assets.get(asset_id="asset123") + runs = await client.async_.runs.list_(assets=[asset.id_], limit=10) + return asset, runs +``` + +## Common Methods + +Most resource APIs provide a consistent set of methods: + +### Query Methods + +- `get()` - Retrieve a single resource by ID or unique identifier +- `list_()` - Retrieve multiple resources with optional filtering +- `find()` - Find a single resource matching criteria (raises error if multiple found) + +### Modification Methods + +- `create()` - Create a new resource (where applicable) +- `update()` - Update an existing resource +- `archive()` - Archive a resource (soft delete) +- `unarchive()` - Restore an archived resource + +## Filtering and Querying + +Resource APIs support powerful filtering capabilities: + +### Common Filters + +- **Name filters**: `name`, `name_contains`, `name_regex` +- **Time filters**: `created_after`, `created_before`, `modified_after`, `modified_before` +- **User filters**: `created_by`, `modified_by` +- **Metadata filters**: `tags`, `metadata` +- **Archive filters**: `include_archived` + +### Resource-Specific Filters + +Each resource API may have additional filters: + +- **Runs**: `start_time_after`, `duration_greater_than`, `is_stopped` +- **Channels**: `asset`, `run` +- **Rules**: `asset_ids`, `asset_tag_ids` + +### Example: Advanced Filtering + +```python +from datetime import datetime, timedelta + +# Complex run query +runs = client.runs.list_( + assets=["asset123"], + start_time_after=datetime.now() - timedelta(days=7), + duration_greater_than=timedelta(hours=1), + is_stopped=True, + tags=["production"], + order_by="start_time desc", + limit=20 +) + +# Channel search with regex +channels = client.channels.list_( + asset="asset123", + name_regex="sensor_[0-9]+_temp", + limit=100 +) +``` + +## Data Retrieval + +The `ChannelsAPI` provides methods for retrieving time-series data: + +```python +from datetime import datetime, timedelta + +# Get channel data as pandas DataFrames +channels = client.channels.list_(asset="asset123", limit=5) +data = client.channels.get_data( + channels=channels, + run="run123", + start_time=datetime.now() - timedelta(hours=1), + end_time=datetime.now(), + limit=10000 +) + +# data is a dict mapping channel names to DataFrames +for channel_name, df in data.items(): + print(f"{channel_name}: {len(df)} data points") + print(df.head()) +``` + +## Async Context Usage + +When using async APIs, ensure proper async context: + +```python +import asyncio +from sift_client import SiftClient + +async def main(): + client = SiftClient(api_key="...", grpc_url="...", rest_url="...") + + # Use async_ accessor for async APIs + assets = await client.async_.assets.list_(limit=10) + + # Concurrent operations + asset_task = client.async_.assets.get(asset_id="asset123") + runs_task = client.async_.runs.list_(limit=10) + + asset, runs = await asyncio.gather(asset_task, runs_task) + + return asset, runs + +# Run the async function +result = asyncio.run(main()) +``` +""" + from sift_client.resources.assets import AssetsAPIAsync from sift_client.resources.calculated_channels import CalculatedChannelsAPIAsync from sift_client.resources.channels import ChannelsAPIAsync From 581afd0ec07d57086432e8d639ba789ce6fe13de Mon Sep 17 00:00:00 2001 From: Alex Luck Date: Fri, 10 Oct 2025 15:57:54 -0700 Subject: [PATCH 5/6] linting --- python/docs/examples/basic.ipynb | 1438 +++++++++++++++--------------- 1 file changed, 726 insertions(+), 712 deletions(-) diff --git a/python/docs/examples/basic.ipynb b/python/docs/examples/basic.ipynb index 268a5466e..d2ebae108 100644 --- a/python/docs/examples/basic.ipynb +++ b/python/docs/examples/basic.ipynb @@ -16,8 +16,9 @@ ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "ef259d05fa338580", + "metadata": {}, "source": [ "## Running this notebook\n", "\n", @@ -31,94 +32,84 @@ "- `matplotlib` for data visualization\n", "\n", "You can install these packages using `pip install notebook rich python-dotenv pandas matplotlib`." - ], - "id": "ef259d05fa338580" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "f2bbc03e85aa2973", + "metadata": {}, "source": [ "## Setup and Initialization\n", "\n", "First, import the necessary modules and initialize the Sift client with your credentials.\n", "\n", "Best practice is to access credentials using environment variables or a `.env` file with `python-dotenv`. Avoid hardcoding your API in any code you write." - ], - "id": "f2bbc03e85aa2973" + ] }, { + "cell_type": "code", + "execution_count": 41, + "id": "497279d83878122e", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:38.990325Z", "start_time": "2025-10-10T21:43:38.928304Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "import os\n", "from datetime import datetime, timedelta\n", - "from rich import print\n", + "\n", "from dotenv import load_dotenv\n", - "from sift_client import SiftClient\n", - "from sift_client.sift_types import (\n", - " ChannelReference,\n", - " CalculatedChannelCreate,\n", - " RuleCreate,\n", - " RuleAction,\n", - " RuleAnnotationType,\n", - ")" - ], - "id": "497279d83878122e", - "outputs": [], - "execution_count": 41 + "from rich import print\n", + "from sift_client import SiftClient" + ] }, { + "cell_type": "code", + "execution_count": 42, + "id": "3492e85e32f1f568", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:39.071502Z", "start_time": "2025-10-10T21:43:39.006349Z" } }, - "cell_type": "code", - "source": [ - "# Get our environment variables\n", - "load_dotenv() # Load environment variables from .env file\n", - "api_key = os.getenv(\"SIFT_API_KEY\")\n", - "grpc_url = os.getenv(\"SIFT_GRPC_URI\")\n", - "rest_url = os.getenv(\"SIFT_REST_URI\")\n", - "\n", - "client = SiftClient(\n", - " api_key=api_key,\n", - " grpc_url=grpc_url,\n", - " rest_url=rest_url\n", - ")\n", - "\n", - "print(\"✓ Sift client initialized successfully\")" - ], - "id": "3492e85e32f1f568", "outputs": [ { "data": { - "text/plain": [ - "✓ Sift client initialized successfully\n" - ], "text/html": [ "
✓ Sift client initialized successfully\n",
        "
\n" + ], + "text/plain": [ + "✓ Sift client initialized successfully\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 42 + "source": [ + "# Get our environment variables\n", + "load_dotenv() # Load environment variables from .env file\n", + "api_key = os.getenv(\"SIFT_API_KEY\")\n", + "grpc_url = os.getenv(\"SIFT_GRPC_URI\")\n", + "rest_url = os.getenv(\"SIFT_REST_URI\")\n", + "\n", + "client = SiftClient(api_key=api_key, grpc_url=grpc_url, rest_url=rest_url)\n", + "\n", + "print(\"✓ Sift client initialized successfully\")" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "378db56e29b1a355", + "metadata": {}, "source": [ "## Sift Resources\n", "\n", @@ -137,19 +128,18 @@ "* etc.\n", "\n", "For example, the `Ping` resource can be used for a basic health check." - ], - "id": "378db56e29b1a355" + ] }, { + "cell_type": "code", + "execution_count": 55, + "id": "fb2db56e076eabec", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:44:59.942480Z", "start_time": "2025-10-10T21:44:59.885641Z" } }, - "cell_type": "code", - "source": "client.ping.ping()", - "id": "fb2db56e076eabec", "outputs": [ { "data": { @@ -162,21 +152,24 @@ "output_type": "execute_result" } ], - "execution_count": 55 + "source": [ + "client.ping.ping()" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "25d1ee945819d7ec", + "metadata": {}, "source": [ "## Assets and Runs\n", "\n", "Assets represent physical or logical entities in your system (e.g., vehicles, machines, devices). Runs represent time-bounded operational periods for an asset (e.g., a flight, a test, a mission)." - ], - "id": "25d1ee945819d7ec" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "894e74a9efdc603e", + "metadata": {}, "source": [ "Resources generally offer similar interaction patterns and methods. For example, the `AssetsAPI` has\n", "* `get`\n", @@ -189,157 +182,136 @@ "Other resources may offer additional methods such as `create`.\n", "\n", "These resource methods operate on and will return Sift object types. More on tehse can be found here: [sift_types](../../reference/sift_client/sift_types/)" - ], - "id": "894e74a9efdc603e" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "86b7b129ccbb2956", + "metadata": {}, "source": [ "## Listing, Finding, and Getting\n", "\n", "`list_` can be used to retrieve objects that match a specific set of criteria:" - ], - "id": "86b7b129ccbb2956" + ] }, { + "cell_type": "code", + "execution_count": 44, + "id": "49992189f605c3e4", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:39.721956Z", "start_time": "2025-10-10T21:43:39.665955Z" } }, - "cell_type": "code", - "source": [ - "# List all assets (limited to 10 for this example)\n", - "assets = client.assets.list_(name_contains=\"Mars\", limit=5)\n", - "for asset in assets:\n", - " print(f\"Name: {asset.name}, ID: {asset.id_}\")\n" - ], - "id": "49992189f605c3e4", "outputs": [ { "data": { - "text/plain": [ - "Name: MarsRoverIngestPusher, ID: \u001B[93m429b864b-0911-4e23-b9d1-2a1fba4d441c\u001B[0m\n" - ], "text/html": [ "
Name: MarsRoverIngestPusher, ID: 429b864b-0911-4e23-b9d1-2a1fba4d441c\n",
        "
\n" + ], + "text/plain": [ + "Name: MarsRoverIngestPusher, ID: \u001b[93m429b864b-0911-4e23-b9d1-2a1fba4d441c\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "Name: Mars Rover \u001B[1m[\u001B[0mJonno export test\u001B[1m]\u001B[0m, ID: \u001B[93m5d86ed46-dec6-41c8-8680-a0ba02d9e546\u001B[0m\n" - ], "text/html": [ "
Name: Mars Rover [Jonno export test], ID: 5d86ed46-dec6-41c8-8680-a0ba02d9e546\n",
        "
\n" + ], + "text/plain": [ + "Name: Mars Rover \u001b[1m[\u001b[0mJonno export test\u001b[1m]\u001b[0m, ID: \u001b[93m5d86ed46-dec6-41c8-8680-a0ba02d9e546\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "Name: MarsRover_pb4, ID: \u001B[93m9bb3bfec-840d-40b7-a5ab-25591f9a1b38\u001B[0m\n" - ], "text/html": [ "
Name: MarsRover_pb4, ID: 9bb3bfec-840d-40b7-a5ab-25591f9a1b38\n",
        "
\n" + ], + "text/plain": [ + "Name: MarsRover_pb4, ID: \u001b[93m9bb3bfec-840d-40b7-a5ab-25591f9a1b38\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "Name: MarsRover, ID: \u001B[93m611914d3-ffb1-402e-ae1e-5eb3e66dea7c\u001B[0m\n" - ], "text/html": [ "
Name: MarsRover, ID: 611914d3-ffb1-402e-ae1e-5eb3e66dea7c\n",
        "
\n" + ], + "text/plain": [ + "Name: MarsRover, ID: \u001b[93m611914d3-ffb1-402e-ae1e-5eb3e66dea7c\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "Name: MarsRover42NaN, ID: \u001B[93m0ad88099-1aea-461c-91b5-0a91c7811f74\u001B[0m\n" - ], "text/html": [ "
Name: MarsRover42NaN, ID: 0ad88099-1aea-461c-91b5-0a91c7811f74\n",
        "
\n" + ], + "text/plain": [ + "Name: MarsRover42NaN, ID: \u001b[93m0ad88099-1aea-461c-91b5-0a91c7811f74\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 44 + "source": [ + "# List all assets (limited to 10 for this example)\n", + "assets = client.assets.list_(name_contains=\"Mars\", limit=5)\n", + "for asset in assets:\n", + " print(f\"Name: {asset.name}, ID: {asset.id_}\")" + ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "`find` can be used to find a single matching object. It will return an error if multiple are found. It takes the same arguments and filters as `list_`.", - "id": "a04618d6724e3a2d" + "id": "a04618d6724e3a2d", + "metadata": {}, + "source": "`find` can be used to find a single matching object. It will return an error if multiple are found. It takes the same arguments and filters as `list_`." }, { + "cell_type": "code", + "execution_count": 45, + "id": "8b4b9ce9b806a576", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:39.790539Z", "start_time": "2025-10-10T21:43:39.732441Z" } }, - "cell_type": "code", - "source": [ - "# Find a specific asset by name\n", - "asset_name = \"MarsRover0\"\n", - "asset = client.assets.find(name=asset_name)\n", - "print(asset)" - ], - "id": "8b4b9ce9b806a576", "outputs": [ { "data": { - "text/plain": [ - "\u001B[1;35mAsset\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'MarsRover0'\u001B[0m,\n", - " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'simulator'\u001B[0m, \u001B[32m'speed-test'\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[32m'vehicle_type'\u001B[0m: \u001B[32m'rover'\u001B[0m, \u001B[32m'vehicle_version'\u001B[0m: \u001B[1;36m123123123.0\u001B[0m, \u001B[32m'version_active'\u001B[0m: \u001B[3;92mTrue\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m1970\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Asset(\n",
        "    id_='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
@@ -355,55 +327,56 @@
        "    archived_date=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mAsset\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'MarsRover0'\u001b[0m,\n", + " \u001b[33morganization_id\u001b[0m=\u001b[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mtags\u001b[0m=\u001b[1m[\u001b[0m\u001b[32m'simulator'\u001b[0m, \u001b[32m'speed-test'\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'vehicle_type'\u001b[0m: \u001b[32m'rover'\u001b[0m, \u001b[32m'vehicle_version'\u001b[0m: \u001b[1;36m123123123.0\u001b[0m, \u001b[32m'version_active'\u001b[0m: \u001b[3;92mTrue\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mis_archived\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33marchived_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m1970\u001b[0m, \u001b[1;36m1\u001b[0m, \u001b[1;36m1\u001b[0m, \u001b[1;36m0\u001b[0m, \u001b[1;36m0\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 45 + "source": [ + "# Find a specific asset by name\n", + "asset_name = \"MarsRover0\"\n", + "asset = client.assets.find(name=asset_name)\n", + "print(asset)" + ] }, { - "metadata": {}, "cell_type": "markdown", - "source": "When we know exactly what we are looking for, we can use `get`.", - "id": "1df0e447f3a04c98" + "id": "1df0e447f3a04c98", + "metadata": {}, + "source": "When we know exactly what we are looking for, we can use `get`." }, { + "cell_type": "code", + "execution_count": 46, + "id": "d8c650d021ff4af8", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:39.857266Z", "start_time": "2025-10-10T21:43:39.798877Z" } }, - "cell_type": "code", - "source": [ - "# Get the exact asset by ID\n", - "asset = client.assets.get(asset_id=asset.id_)\n", - "print(asset)" - ], - "id": "d8c650d021ff4af8", "outputs": [ { "data": { - "text/plain": [ - "\u001B[1;35mAsset\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'MarsRover0'\u001B[0m,\n", - " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[32m'simulator'\u001B[0m, \u001B[32m'speed-test'\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[32m'vehicle_type'\u001B[0m: \u001B[32m'rover'\u001B[0m, \u001B[32m'vehicle_version'\u001B[0m: \u001B[1;36m123123123.0\u001B[0m, \u001B[32m'version_active'\u001B[0m: \u001B[3;92mTrue\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m1970\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m1\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[1;36m0\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Asset(\n",
        "    id_='61d6e4f0-8287-4678-b071-18a95fcd9db6',\n",
@@ -419,74 +392,61 @@
        "    archived_date=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mAsset\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'MarsRover0'\u001b[0m,\n", + " \u001b[33morganization_id\u001b[0m=\u001b[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mtags\u001b[0m=\u001b[1m[\u001b[0m\u001b[32m'simulator'\u001b[0m, \u001b[32m'speed-test'\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'vehicle_type'\u001b[0m: \u001b[32m'rover'\u001b[0m, \u001b[32m'vehicle_version'\u001b[0m: \u001b[1;36m123123123.0\u001b[0m, \u001b[32m'version_active'\u001b[0m: \u001b[3;92mTrue\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mis_archived\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33marchived_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m1970\u001b[0m, \u001b[1;36m1\u001b[0m, \u001b[1;36m1\u001b[0m, \u001b[1;36m0\u001b[0m, \u001b[1;36m0\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 46 + "source": [ + "# Get the exact asset by ID\n", + "asset = client.assets.get(asset_id=asset.id_)\n", + "print(asset)" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "e8ebf9754df8f646", + "metadata": {}, "source": [ "## Creating, Updating, and Archiving\n", "\n", "Most resources offer `create`, `update`, and `archive` methods.\n", "\n", "Since `create` returns a `Run`, we can chain `update` and `archive` on it and the Sift object will update in-place." - ], - "id": "e8ebf9754df8f646" + ] }, { + "cell_type": "code", + "execution_count": 47, + "id": "143bafd4b2a5edb5", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:39.914350Z", "start_time": "2025-10-10T21:43:39.860934Z" } }, - "cell_type": "code", - "source": [ - "# Run creation\n", - "run = client.runs.create(dict(\n", - " name=\"Test Run\",\n", - " description=\"A test run\",\n", - " asset_ids=[asset.id_],\n", - " start_time=datetime.now())\n", - ")\n", - "print(run)" - ], - "id": "143bafd4b2a5edb5", "outputs": [ { "data": { - "text/plain": [ - "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'Test Run'\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'A test run'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m913134\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m915093\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", - " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m861550\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m54929\u001B[0m\u001B[1m)\u001B[0m,\n", - " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001B[0m,\n", - " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Run(\n",
        "    id_='523c6f2a-181c-4ee7-8876-421901daf97f',\n",
@@ -510,60 +470,61 @@
        "    archived_date=None\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mRun\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'Test Run'\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'A test run'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m913134\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m915093\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33morganization_id\u001b[0m=\u001b[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mtags\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33masset_ids\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mis_adhoc\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mis_archived\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mstart_time\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m861550\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mstop_time\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mduration\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.timedelta\u001b[0m\u001b[1m(\u001b[0m\u001b[33mseconds\u001b[0m=\u001b[1;36m25200\u001b[0m, \u001b[33mmicroseconds\u001b[0m=\u001b[1;36m54929\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[33mdefault_report_id\u001b[0m=\u001b[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001b[0m,\n", + " \u001b[33mclient_key\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33marchived_date\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 47 + "source": [ + "# Run creation\n", + "run = client.runs.create(\n", + " dict(\n", + " name=\"Test Run\", description=\"A test run\", asset_ids=[asset.id_], start_time=datetime.now()\n", + " )\n", + ")\n", + "print(run)" + ] }, { + "cell_type": "code", + "execution_count": 48, + "id": "22ad6199aeb8cc5d", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:39.983767Z", "start_time": "2025-10-10T21:43:39.922700Z" } }, - "cell_type": "code", - "source": [ - "# Run update\n", - "run.update(dict(\n", - " name=\"Updated Test Run\",\n", - " description=\"An updated test run\", )\n", - ")\n", - "print(run)" - ], - "id": "22ad6199aeb8cc5d", "outputs": [ { "data": { - "text/plain": [ - "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'Updated Test Run'\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'An updated test run'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m913134\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m981793\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", - " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33mis_archived\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m861550\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m123957\u001B[0m\u001B[1m)\u001B[0m,\n", - " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001B[0m,\n", - " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33marchived_date\u001B[0m=\u001B[3;35mNone\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Run(\n",
        "    id_='523c6f2a-181c-4ee7-8876-421901daf97f',\n",
@@ -587,57 +548,62 @@
        "    archived_date=None\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mRun\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'Updated Test Run'\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'An updated test run'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m913134\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m981793\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33morganization_id\u001b[0m=\u001b[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mtags\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33masset_ids\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mis_adhoc\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mis_archived\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mstart_time\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m861550\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mstop_time\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mduration\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.timedelta\u001b[0m\u001b[1m(\u001b[0m\u001b[33mseconds\u001b[0m=\u001b[1;36m25200\u001b[0m, \u001b[33mmicroseconds\u001b[0m=\u001b[1;36m123957\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[33mdefault_report_id\u001b[0m=\u001b[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001b[0m,\n", + " \u001b[33mclient_key\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33marchived_date\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 48 + "source": [ + "# Run update\n", + "run.update(\n", + " dict(\n", + " name=\"Updated Test Run\",\n", + " description=\"An updated test run\",\n", + " )\n", + ")\n", + "print(run)" + ] }, { + "cell_type": "code", + "execution_count": 49, + "id": "3d24afef7771f010", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:40.057415Z", "start_time": "2025-10-10T21:43:39.988773Z" } }, - "cell_type": "code", - "source": [ - "# Run archive\n", - "run.archive()\n", - "print(run)" - ], - "id": "3d24afef7771f010", "outputs": [ { "data": { - "text/plain": [ - "\u001B[1;35mRun\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'Updated Test Run'\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'An updated test run'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m913134\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m40\u001B[0m, \u001B[1;36m52001\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001B[0m,\n", - " \u001B[33morganization_id\u001B[0m=\u001B[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001B[0m,\n", - " \u001B[33mmetadata\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33mtags\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33masset_ids\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33mis_adhoc\u001B[0m=\u001B[3;91mFalse\u001B[0m,\n", - " \u001B[33mis_archived\u001B[0m=\u001B[3;92mTrue\u001B[0m,\n", - " \u001B[33mstart_time\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m14\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m39\u001B[0m, \u001B[1;36m861550\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mstop_time\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33mduration\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.timedelta\u001B[0m\u001B[1m(\u001B[0m\u001B[33mseconds\u001B[0m=\u001B[1;36m25200\u001B[0m, \u001B[33mmicroseconds\u001B[0m=\u001B[1;36m196350\u001B[0m\u001B[1m)\u001B[0m,\n", - " \u001B[33mdefault_report_id\u001B[0m=\u001B[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001B[0m,\n", - " \u001B[33mclient_key\u001B[0m=\u001B[3;35mNone\u001B[0m,\n", - " \u001B[33marchived_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m10\u001B[0m, \u001B[1;36m21\u001B[0m, \u001B[1;36m43\u001B[0m, \u001B[1;36m40\u001B[0m, \u001B[1;36m48186\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Run(\n",
        "    id_='523c6f2a-181c-4ee7-8876-421901daf97f',\n",
@@ -661,86 +627,83 @@
        "    archived_date=datetime.datetime(2025, 10, 10, 21, 43, 40, 48186, tzinfo=datetime.timezone.utc)\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mRun\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'523c6f2a-181c-4ee7-8876-421901daf97f'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'Updated Test Run'\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'An updated test run'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m913134\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m40\u001b[0m, \u001b[1;36m52001\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33morganization_id\u001b[0m=\u001b[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mtags\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33masset_ids\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mis_adhoc\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mis_archived\u001b[0m=\u001b[3;92mTrue\u001b[0m,\n", + " \u001b[33mstart_time\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m39\u001b[0m, \u001b[1;36m861550\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mstop_time\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mduration\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.timedelta\u001b[0m\u001b[1m(\u001b[0m\u001b[33mseconds\u001b[0m=\u001b[1;36m25200\u001b[0m, \u001b[33mmicroseconds\u001b[0m=\u001b[1;36m196350\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[33mdefault_report_id\u001b[0m=\u001b[32m'854787b6-4e38-4c81-bdf0-8d143c791d01'\u001b[0m,\n", + " \u001b[33mclient_key\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33marchived_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m43\u001b[0m, \u001b[1;36m40\u001b[0m, \u001b[1;36m48186\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 49 + "source": [ + "# Run archive\n", + "run.archive()\n", + "print(run)" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "c1830f179b22cb43", + "metadata": {}, "source": [ "## Searching Channels\n", "\n", "Channels represent time-series data streams (e.g., sensor readings, telemetry)." - ], - "id": "c1830f179b22cb43" + ] }, { + "cell_type": "code", + "execution_count": 50, + "id": "9c5a1b60c0fce9fc", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:40.313373Z", "start_time": "2025-10-10T21:43:40.062560Z" } }, - "cell_type": "code", - "source": [ - "# List channels for the selected asset\n", - "channels = client.channels.list_(\n", - " asset=asset.id_,\n", - " limit=5\n", - ")\n", - "\n", - "print(f\"Found {len(channels)} channels for asset '{asset.name}':\")\n", - "for channel in channels: # Show first 10\n", - " print(channel)\n", - " # if channel.description:\n", - " # print(f\" Description: {channel.description}\")\n", - " # if channel.units:\n", - " # print(f\" Units: {channel.units}\")" - ], - "id": "9c5a1b60c0fce9fc", "outputs": [ { "data": { - "text/plain": [ - "Found \u001B[1;36m5\u001B[0m channels for asset \u001B[32m'MarsRover0'\u001B[0m:\n" - ], "text/html": [ "
Found 5 channels for asset 'MarsRover0':\n",
        "
\n" + ], + "text/plain": [ + "Found \u001b[1;36m5\u001b[0m channels for asset \u001b[32m'MarsRover0'\u001b[0m:\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'0f1a32d4-0f97-494f-82f8-2ed7f3983e74'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'is_even'\u001B[0m,\n", - " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.BOOL:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m5\u001B[0m\u001B[1m>\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'is the value of milliseconds even'\u001B[0m,\n", - " \u001B[33munit\u001B[0m=\u001B[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001B[0m,\n", - " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Channel(\n",
        "    id_='0f1a32d4-0f97-494f-82f8-2ed7f3983e74',\n",
@@ -757,32 +720,32 @@
        "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'0f1a32d4-0f97-494f-82f8-2ed7f3983e74'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'is_even'\u001b[0m,\n", + " \u001b[33mdata_type\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mChannelDataType.BOOL:\u001b[0m\u001b[39m \u001b[0m\u001b[1;36m5\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'is the value of milliseconds even'\u001b[0m,\n", + " \u001b[33munit\u001b[0m=\u001b[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001b[0m,\n", + " \u001b[33mbit_field_elements\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33menum_types\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33masset_id\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'1c2dd815-2c9e-4801-92dc-1f65cad2114b'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'voltage'\u001B[0m,\n", - " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.INT_32:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m7\u001B[0m\u001B[1m>\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'voltage at the source'\u001B[0m,\n", - " \u001B[33munit\u001B[0m=\u001B[32m'09f1005b-df6a-4f82-838f-c57e77c587ef'\u001B[0m,\n", - " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Channel(\n",
        "    id_='1c2dd815-2c9e-4801-92dc-1f65cad2114b',\n",
@@ -799,32 +762,32 @@
        "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'1c2dd815-2c9e-4801-92dc-1f65cad2114b'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'voltage'\u001b[0m,\n", + " \u001b[33mdata_type\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mChannelDataType.INT_32:\u001b[0m\u001b[39m \u001b[0m\u001b[1;36m7\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'voltage at the source'\u001b[0m,\n", + " \u001b[33munit\u001b[0m=\u001b[32m'09f1005b-df6a-4f82-838f-c57e77c587ef'\u001b[0m,\n", + " \u001b[33mbit_field_elements\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33menum_types\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33masset_id\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'606817a0-396e-4575-9ffc-45a4ef9ca66a'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'log'\u001B[0m,\n", - " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.STRING:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m2\u001B[0m\u001B[1m>\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'this simulates log files'\u001B[0m,\n", - " \u001B[33munit\u001B[0m=\u001B[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001B[0m,\n", - " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Channel(\n",
        "    id_='606817a0-396e-4575-9ffc-45a4ef9ca66a',\n",
@@ -841,32 +804,32 @@
        "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'606817a0-396e-4575-9ffc-45a4ef9ca66a'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'log'\u001b[0m,\n", + " \u001b[33mdata_type\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mChannelDataType.STRING:\u001b[0m\u001b[39m \u001b[0m\u001b[1;36m2\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'this simulates log files'\u001b[0m,\n", + " \u001b[33munit\u001b[0m=\u001b[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001b[0m,\n", + " \u001b[33mbit_field_elements\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33menum_types\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33masset_id\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'mainmotor.velocity'\u001B[0m,\n", - " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.DOUBLE:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m1\u001B[0m\u001B[1m>\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'speed'\u001B[0m,\n", - " \u001B[33munit\u001B[0m=\u001B[32m'b840c8e8-33fb-433c-9448-07577f04e990'\u001B[0m,\n", - " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Channel(\n",
        "    id_='a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7',\n",
@@ -883,37 +846,32 @@
        "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'mainmotor.velocity'\u001b[0m,\n", + " \u001b[33mdata_type\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mChannelDataType.DOUBLE:\u001b[0m\u001b[39m \u001b[0m\u001b[1;36m1\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'speed'\u001b[0m,\n", + " \u001b[33munit\u001b[0m=\u001b[32m'b840c8e8-33fb-433c-9448-07577f04e990'\u001b[0m,\n", + " \u001b[33mbit_field_elements\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33menum_types\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33masset_id\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'c052cef4-d3eb-486e-b3cb-63b59504e913'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'gpio'\u001B[0m,\n", - " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.BIT_FIELD:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m4\u001B[0m\u001B[1m>\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'on/off values for pins on gpio'\u001B[0m,\n", - " \u001B[33munit\u001B[0m=\u001B[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001B[0m,\n", - " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\n", - " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'12v'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m0\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m1\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'charge'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m1\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m2\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'led'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m3\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m4\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[1m{\u001B[0m\u001B[32m'name'\u001B[0m: \u001B[32m'heater'\u001B[0m, \u001B[32m'index'\u001B[0m: \u001B[1;36m7\u001B[0m, \u001B[32m'bit_count'\u001B[0m: \u001B[1;36m1\u001B[0m\u001B[1m}\u001B[0m\n", - " \u001B[1m]\u001B[0m,\n", - " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Channel(\n",
        "    id_='c052cef4-d3eb-486e-b3cb-63b59504e913',\n",
@@ -935,74 +893,74 @@
        "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'c052cef4-d3eb-486e-b3cb-63b59504e913'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'gpio'\u001b[0m,\n", + " \u001b[33mdata_type\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mChannelDataType.BIT_FIELD:\u001b[0m\u001b[39m \u001b[0m\u001b[1;36m4\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'on/off values for pins on gpio'\u001b[0m,\n", + " \u001b[33munit\u001b[0m=\u001b[32m'0c359676-c6c9-47d3-acca-d8e938311b2a'\u001b[0m,\n", + " \u001b[33mbit_field_elements\u001b[0m=\u001b[1m[\u001b[0m\n", + " \u001b[1m{\u001b[0m\u001b[32m'name'\u001b[0m: \u001b[32m'12v'\u001b[0m, \u001b[32m'index'\u001b[0m: \u001b[1;36m0\u001b[0m, \u001b[32m'bit_count'\u001b[0m: \u001b[1;36m1\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[1m{\u001b[0m\u001b[32m'name'\u001b[0m: \u001b[32m'charge'\u001b[0m, \u001b[32m'index'\u001b[0m: \u001b[1;36m1\u001b[0m, \u001b[32m'bit_count'\u001b[0m: \u001b[1;36m2\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[1m{\u001b[0m\u001b[32m'name'\u001b[0m: \u001b[32m'led'\u001b[0m, \u001b[32m'index'\u001b[0m: \u001b[1;36m3\u001b[0m, \u001b[32m'bit_count'\u001b[0m: \u001b[1;36m4\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[1m{\u001b[0m\u001b[32m'name'\u001b[0m: \u001b[32m'heater'\u001b[0m, \u001b[32m'index'\u001b[0m: \u001b[1;36m7\u001b[0m, \u001b[32m'bit_count'\u001b[0m: \u001b[1;36m1\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1m]\u001b[0m,\n", + " \u001b[33menum_types\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33masset_id\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 50 + "source": [ + "# List channels for the selected asset\n", + "channels = client.channels.list_(asset=asset.id_, limit=5)\n", + "\n", + "print(f\"Found {len(channels)} channels for asset '{asset.name}':\")\n", + "for channel in channels: # Show first 10\n", + " print(channel)" + ] }, { + "cell_type": "code", + "execution_count": 51, + "id": "c2317d7f561926d6", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:40.414219Z", "start_time": "2025-10-10T21:43:40.325320Z" } }, - "cell_type": "code", - "source": [ - "# Search for specific channels by name pattern\n", - "# Replace with a pattern that matches your channel names\n", - "velocity_channels = client.channels.list_(\n", - " asset=asset.id_,\n", - " name_contains=\"velocity\",\n", - " limit=10\n", - ")\n", - "\n", - "print(f\"Channels containing 'velocity': {len(velocity_channels)}\")\n", - "for ch in velocity_channels:\n", - " print(ch)" - ], - "id": "c2317d7f561926d6", "outputs": [ { "data": { - "text/plain": [ - "Channels containing \u001B[32m'velocity'\u001B[0m: \u001B[1;36m1\u001B[0m\n" - ], "text/html": [ "
Channels containing 'velocity': 1\n",
        "
\n" + ], + "text/plain": [ + "Channels containing \u001b[32m'velocity'\u001b[0m: \u001b[1;36m1\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\u001B[1;35mChannel\u001B[0m\u001B[1m(\u001B[0m\n", - " \u001B[33mid_\u001B[0m=\u001B[32m'a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7'\u001B[0m,\n", - " \u001B[33mname\u001B[0m=\u001B[32m'mainmotor.velocity'\u001B[0m,\n", - " \u001B[33mdata_type\u001B[0m=\u001B[1m<\u001B[0m\u001B[1;95mChannelDataType.DOUBLE:\u001B[0m\u001B[39m \u001B[0m\u001B[1;36m1\u001B[0m\u001B[1m>\u001B[0m,\n", - " \u001B[33mdescription\u001B[0m=\u001B[32m'speed'\u001B[0m,\n", - " \u001B[33munit\u001B[0m=\u001B[32m'b840c8e8-33fb-433c-9448-07577f04e990'\u001B[0m,\n", - " \u001B[33mbit_field_elements\u001B[0m=\u001B[1m[\u001B[0m\u001B[1m]\u001B[0m,\n", - " \u001B[33menum_types\u001B[0m=\u001B[1m{\u001B[0m\u001B[1m}\u001B[0m,\n", - " \u001B[33masset_id\u001B[0m=\u001B[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001B[0m,\n", - " \u001B[33mcreated_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mmodified_date\u001B[0m=\u001B[1;35mdatetime\u001B[0m\u001B[1;35m.datetime\u001B[0m\u001B[1m(\u001B[0m\u001B[1;36m2025\u001B[0m, \u001B[1;36m3\u001B[0m, \u001B[1;36m4\u001B[0m, \u001B[1;36m19\u001B[0m, \u001B[1;36m51\u001B[0m, \u001B[1;36m15\u001B[0m, \u001B[1;36m89746\u001B[0m, \u001B[33mtzinfo\u001B[0m=\u001B[35mdatetime\u001B[0m.timezone.utc\u001B[1m)\u001B[0m,\n", - " \u001B[33mcreated_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m,\n", - " \u001B[33mmodified_by_user_id\u001B[0m=\u001B[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001B[0m\n", - "\u001B[1m)\u001B[0m\n" - ], "text/html": [ "
Channel(\n",
        "    id_='a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7',\n",
@@ -1019,159 +977,153 @@
        "    modified_by_user_id='f47e4854-234b-421c-badb-7f8bb757cd9d'\n",
        ")\n",
        "
\n" + ], + "text/plain": [ + "\u001b[1;35mChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'a59c4ec4-5e8c-4457-8a41-ecbc06b0dca7'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'mainmotor.velocity'\u001b[0m,\n", + " \u001b[33mdata_type\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mChannelDataType.DOUBLE:\u001b[0m\u001b[39m \u001b[0m\u001b[1;36m1\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'speed'\u001b[0m,\n", + " \u001b[33munit\u001b[0m=\u001b[32m'b840c8e8-33fb-433c-9448-07577f04e990'\u001b[0m,\n", + " \u001b[33mbit_field_elements\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33menum_types\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33masset_id\u001b[0m=\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m4\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m51\u001b[0m, \u001b[1;36m15\u001b[0m, \u001b[1;36m89746\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'f47e4854-234b-421c-badb-7f8bb757cd9d'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 51 + "source": [ + "# Search for specific channels by name pattern\n", + "# Replace with a pattern that matches your channel names\n", + "velocity_channels = client.channels.list_(asset=asset.id_, name_contains=\"velocity\", limit=10)\n", + "\n", + "print(f\"Channels containing 'velocity': {len(velocity_channels)}\")\n", + "for ch in velocity_channels:\n", + " print(ch)" + ] }, { + "cell_type": "code", + "execution_count": 52, + "id": "1601a55853281e95", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:40.482064Z", "start_time": "2025-10-10T21:43:40.429852Z" } }, - "cell_type": "code", - "source": [ - "# Get channels for a specific run. There should be none since we just created it.\n", - "if run:\n", - " run_channels = client.channels.list_(\n", - " run=run.id_,\n", - " limit=10\n", - " )\n", - " print(f\"Channels in run '{run.name}': {len(run_channels)}\")\n", - " for ch in run_channels:\n", - " print(f\" - {ch.name}\")" - ], - "id": "1601a55853281e95", "outputs": [ { "data": { - "text/plain": [ - "Channels in run \u001B[32m'Updated Test Run'\u001B[0m: \u001B[1;36m0\u001B[0m\n" - ], "text/html": [ "
Channels in run 'Updated Test Run': 0\n",
        "
\n" + ], + "text/plain": [ + "Channels in run \u001b[32m'Updated Test Run'\u001b[0m: \u001b[1;36m0\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 52 + "source": [ + "# Get channels for a specific run. There should be none since we just created it.\n", + "if run:\n", + " run_channels = client.channels.list_(run=run.id_, limit=10)\n", + " print(f\"Channels in run '{run.name}': {len(run_channels)}\")\n", + " for ch in run_channels:\n", + " print(f\" - {ch.name}\")" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "7c611ee731605cbd", + "metadata": {}, "source": [ "## Pulling Data\n", "\n", "Retrieve time-series data from channels as pandas DataFrames." - ], - "id": "7c611ee731605cbd" + ] }, { + "cell_type": "code", + "execution_count": 53, + "id": "b6b40678b0bbe34e", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:40.980438Z", "start_time": "2025-10-10T21:43:40.491510Z" } }, - "cell_type": "code", - "source": [ - "run = client.runs.list_(duration_greater_than=timedelta(seconds=30),\n", - " description_contains=\"simulated run: 1 flows, 8 total channels, 5hz sampling rate\")[0]\n", - "\n", - "# Get data for specific channels\n", - "\n", - "\n", - "# Get data as a dictionary of pandas DataFrames\n", - "data = client.channels.get_data(\n", - " channels=client.channels.list_(run=run, name_contains=\"v\"),\n", - " run=run,\n", - " limit=1000 # Limit to 1000 data points per channel\n", - ")\n", - "\n", - "print(f\"\\n✓ Retrieved data for {len(data)} channels:\")\n", - "for channel_name, df in data.items():\n", - " print(f\"\\n Channel: {channel_name}\")\n", - " print(f\" Data points: {len(df)}\")\n", - " print(df.head())\n" - ], - "id": "b6b40678b0bbe34e", "outputs": [ { "data": { - "text/plain": [ - "\n", - "✓ Retrieved data for \u001B[1;36m4\u001B[0m channels:\n" - ], "text/html": [ "
\n",
        "✓ Retrieved data for 4 channels:\n",
        "
\n" + ], + "text/plain": [ + "\n", + "✓ Retrieved data for \u001b[1;36m4\u001b[0m channels:\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\n", - " Channel: is_even\n" - ], "text/html": [ "
\n",
        "  Channel: is_even\n",
        "
\n" + ], + "text/plain": [ + "\n", + " Channel: is_even\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " Data points: \u001B[1;36m1000\u001B[0m\n" - ], "text/html": [ "
  Data points: 1000\n",
        "
\n" + ], + "text/plain": [ + " Data points: \u001b[1;36m1000\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " is_even\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[3;92mTrue\u001B[0m\n" - ], "text/html": [ "
                                     is_even\n",
        "2025-06-04 17:21:13.180486958+00:00     True\n",
@@ -1180,58 +1132,58 @@
        "2025-06-04 17:21:13.780486958+00:00     True\n",
        "2025-06-04 17:21:13.980486958+00:00     True\n",
        "
\n" + ], + "text/plain": [ + " is_even\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m180486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[3;92mTrue\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m380486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[3;92mTrue\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m580486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[3;92mTrue\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m780486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[3;92mTrue\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m980486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[3;92mTrue\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\n", - " Channel: mainmotor.velocity\n" - ], "text/html": [ "
\n",
        "  Channel: mainmotor.velocity\n",
        "
\n" + ], + "text/plain": [ + "\n", + " Channel: mainmotor.velocity\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " Data points: \u001B[1;36m1000\u001B[0m\n" - ], "text/html": [ "
  Data points: 1000\n",
        "
\n" + ], + "text/plain": [ + " Data points: \u001b[1;36m1000\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " mainmotor.velocity\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m21.352492\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m32.011998\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m34.370449\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m25.635827\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m16.148490\u001B[0m\n" - ], "text/html": [ "
                                     mainmotor.velocity\n",
        "2025-06-04 17:21:13.180486958+00:00           21.352492\n",
@@ -1240,58 +1192,58 @@
        "2025-06-04 17:21:13.780486958+00:00           25.635827\n",
        "2025-06-04 17:21:13.980486958+00:00           16.148490\n",
        "
\n" + ], + "text/plain": [ + " mainmotor.velocity\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m180486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m21.352492\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m380486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m32.011998\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m580486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m34.370449\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m780486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m25.635827\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m980486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m16.148490\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\n", - " Channel: vehicle_state\n" - ], "text/html": [ "
\n",
        "  Channel: vehicle_state\n",
        "
\n" + ], + "text/plain": [ + "\n", + " Channel: vehicle_state\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " Data points: \u001B[1;36m1000\u001B[0m\n" - ], "text/html": [ "
  Data points: 1000\n",
        "
\n" + ], + "text/plain": [ + " Data points: \u001b[1;36m1000\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " vehicle_state\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m1\u001B[0m\n" - ], "text/html": [ "
                                     vehicle_state\n",
        "2025-06-04 17:21:13.180486958+00:00              1\n",
@@ -1300,58 +1252,58 @@
        "2025-06-04 17:21:13.780486958+00:00              1\n",
        "2025-06-04 17:21:13.980486958+00:00              1\n",
        "
\n" + ], + "text/plain": [ + " vehicle_state\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m180486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m1\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m380486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m1\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m580486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m1\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m780486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m1\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m980486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m1\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\n", - " Channel: voltage\n" - ], "text/html": [ "
\n",
        "  Channel: voltage\n",
        "
\n" + ], + "text/plain": [ + "\n", + " Channel: voltage\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " Data points: \u001B[1;36m1000\u001B[0m\n" - ], "text/html": [ "
  Data points: 1000\n",
        "
\n" + ], + "text/plain": [ + " Data points: \u001b[1;36m1000\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " voltage\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m180486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m12\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m380486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m12\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m580486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m12\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m780486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m2\u001B[0m\n", - "\u001B[1;36m2025\u001B[0m-\u001B[1;36m06\u001B[0m-\u001B[1;36m04\u001B[0m \u001B[1;92m17:21:13\u001B[0m.\u001B[1;36m980486958\u001B[0m+\u001B[1;92m00:00\u001B[0m \u001B[1;36m2\u001B[0m\n" - ], "text/html": [ "
                                     voltage\n",
        "2025-06-04 17:21:13.180486958+00:00       12\n",
@@ -1360,35 +1312,147 @@
        "2025-06-04 17:21:13.780486958+00:00        2\n",
        "2025-06-04 17:21:13.980486958+00:00        2\n",
        "
\n" + ], + "text/plain": [ + " voltage\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m180486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m12\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m380486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m12\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m580486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m12\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m780486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m2\u001b[0m\n", + "\u001b[1;36m2025\u001b[0m-\u001b[1;36m06\u001b[0m-\u001b[1;36m04\u001b[0m \u001b[1;92m17:21:13\u001b[0m.\u001b[1;36m980486958\u001b[0m+\u001b[1;92m00:00\u001b[0m \u001b[1;36m2\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 53 + "source": [ + "run = client.runs.list_(\n", + " duration_greater_than=timedelta(seconds=30),\n", + " description_contains=\"simulated run: 1 flows, 8 total channels, 5hz sampling rate\",\n", + ")[0]\n", + "\n", + "# Get data as a dictionary of pandas DataFrames\n", + "data = client.channels.get_data(\n", + " channels=client.channels.list_(run=run, name_contains=\"v\"),\n", + " run=run,\n", + " limit=1000, # Limit to 1000 data points per channel\n", + ")\n", + "\n", + "print(f\"\\n✓ Retrieved data for {len(data)} channels:\")\n", + "for channel_name, df in data.items():\n", + " print(f\"\\n Channel: {channel_name}\")\n", + " print(f\" Data points: {len(df)}\")\n", + " print(df.head())" + ] }, { - "metadata": {}, "cell_type": "markdown", + "id": "b6c81e31a31fdc03", + "metadata": {}, "source": [ "## Creating Calculated Channels\n", "\n", "Calculated channels allow you to create derived metrics from existing channels using mathematical expressions." - ], - "id": "b6c81e31a31fdc03" + ] }, { + "cell_type": "code", + "execution_count": 58, + "id": "70a5b0d39e5230c4", "metadata": { "ExecuteTime": { - "end_time": "2025-10-10T21:43:41.254295Z", - "start_time": "2025-10-10T21:43:41.100146Z" + "end_time": "2025-10-10T22:56:15.431423Z", + "start_time": "2025-10-10T22:56:15.154065Z" } }, - "cell_type": "code", + "outputs": [ + { + "data": { + "text/html": [ + "
Calculated channel 'is_even_per_voltage' already exists\n",
+       "
\n" + ], + "text/plain": [ + "Calculated channel \u001b[32m'is_even_per_voltage'\u001b[0m already exists\n" + ] + }, + "jetTransient": { + "display_id": null + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
CalculatedChannel(\n",
+       "    id_='d283b5fe-fed5-4260-93d1-8bd65bec4bfe',\n",
+       "    name='is_even_per_voltage',\n",
+       "    description='Ratio of is_even to voltage',\n",
+       "    expression='$1 / $2',\n",
+       "    channel_references=[\n",
+       "        {'channel_reference': '$1', 'channel_identifier': 'is_even'},\n",
+       "        {'channel_reference': '$2', 'channel_identifier': 'voltage'}\n",
+       "    ],\n",
+       "    is_archived=True,\n",
+       "    units='',\n",
+       "    asset_ids=['61d6e4f0-8287-4678-b071-18a95fcd9db6'],\n",
+       "    tag_ids=[],\n",
+       "    all_assets=False,\n",
+       "    organization_id='dd9f82ef-7805-4b02-9572-ec61b71edde6',\n",
+       "    client_key='',\n",
+       "    archived_date=datetime.datetime(2025, 10, 10, 21, 36, 19, 947790, tzinfo=datetime.timezone.utc),\n",
+       "    version_id='0923ec64-9799-4e73-8038-71496227a846',\n",
+       "    version=1,\n",
+       "    change_message='Created calculated channel',\n",
+       "    user_notes='',\n",
+       "    created_date=datetime.datetime(2025, 10, 10, 21, 34, 3, 533939, tzinfo=datetime.timezone.utc),\n",
+       "    modified_date=datetime.datetime(2025, 10, 10, 21, 34, 3, 533939, tzinfo=datetime.timezone.utc),\n",
+       "    created_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c',\n",
+       "    modified_by_user_id='ae1f6c7c-3e93-40a9-8796-d227a725662c'\n",
+       ")\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1;35mCalculatedChannel\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid_\u001b[0m=\u001b[32m'd283b5fe-fed5-4260-93d1-8bd65bec4bfe'\u001b[0m,\n", + " \u001b[33mname\u001b[0m=\u001b[32m'is_even_per_voltage'\u001b[0m,\n", + " \u001b[33mdescription\u001b[0m=\u001b[32m'Ratio of is_even to voltage'\u001b[0m,\n", + " \u001b[33mexpression\u001b[0m=\u001b[32m'$1 / $2'\u001b[0m,\n", + " \u001b[33mchannel_references\u001b[0m=\u001b[1m[\u001b[0m\n", + " \u001b[1m{\u001b[0m\u001b[32m'channel_reference'\u001b[0m: \u001b[32m'$1'\u001b[0m, \u001b[32m'channel_identifier'\u001b[0m: \u001b[32m'is_even'\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[1m{\u001b[0m\u001b[32m'channel_reference'\u001b[0m: \u001b[32m'$2'\u001b[0m, \u001b[32m'channel_identifier'\u001b[0m: \u001b[32m'voltage'\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1m]\u001b[0m,\n", + " \u001b[33mis_archived\u001b[0m=\u001b[3;92mTrue\u001b[0m,\n", + " \u001b[33munits\u001b[0m=\u001b[32m''\u001b[0m,\n", + " \u001b[33masset_ids\u001b[0m=\u001b[1m[\u001b[0m\u001b[32m'61d6e4f0-8287-4678-b071-18a95fcd9db6'\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mtag_ids\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mall_assets\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33morganization_id\u001b[0m=\u001b[32m'dd9f82ef-7805-4b02-9572-ec61b71edde6'\u001b[0m,\n", + " \u001b[33mclient_key\u001b[0m=\u001b[32m''\u001b[0m,\n", + " \u001b[33marchived_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m36\u001b[0m, \u001b[1;36m19\u001b[0m, \u001b[1;36m947790\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mversion_id\u001b[0m=\u001b[32m'0923ec64-9799-4e73-8038-71496227a846'\u001b[0m,\n", + " \u001b[33mversion\u001b[0m=\u001b[1;36m1\u001b[0m,\n", + " \u001b[33mchange_message\u001b[0m=\u001b[32m'Created calculated channel'\u001b[0m,\n", + " \u001b[33muser_notes\u001b[0m=\u001b[32m''\u001b[0m,\n", + " \u001b[33mcreated_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m34\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m533939\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mmodified_date\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m10\u001b[0m, \u001b[1;36m21\u001b[0m, \u001b[1;36m34\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m533939\u001b[0m, \u001b[33mtzinfo\u001b[0m=\u001b[35mdatetime\u001b[0m.timezone.utc\u001b[1m)\u001b[0m,\n", + " \u001b[33mcreated_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m,\n", + " \u001b[33mmodified_by_user_id\u001b[0m=\u001b[32m'ae1f6c7c-3e93-40a9-8796-d227a725662c'\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" + ] + }, + "jetTransient": { + "display_id": null + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "# Create a calculated channel\n", "# This example creates a channel that divides two existing channels\n", @@ -1403,8 +1467,7 @@ "\n", "# Check if calculated channel already exists\n", "existing = client.calculated_channels.find(\n", - " name=calc_channel_name,\n", - " asset=asset.id_\n", + " name=calc_channel_name, asset=asset.id_, include_archived=True\n", ")\n", "\n", "if existing:\n", @@ -1419,208 +1482,159 @@ " description=f\"Ratio of {channel1.name} to {channel2.name}\",\n", " expression=\"$1 / $2\", # $1 and $2 refer to the channel references below\n", " expression_channel_references=[\n", - " dict(\n", - " channel_reference=\"$1\",\n", - " channel_identifier=channel1.name\n", - " ),\n", - " dict(\n", - " channel_reference=\"$2\",\n", - " channel_identifier=channel2.name\n", - " ),\n", + " dict(channel_reference=\"$1\", channel_identifier=channel1.name),\n", + " dict(channel_reference=\"$2\", channel_identifier=channel2.name),\n", " ],\n", " asset_ids=[asset.id_],\n", " )\n", " )\n", "\n", - " print(calc_channel)\n" - ], - "id": "70a5b0d39e5230c4", - "outputs": [ - { - "data": { - "text/plain": [ - "Creating calculated channel: is_even_per_voltage\n" - ], - "text/html": [ - "
Creating calculated channel: is_even_per_voltage\n",
-       "
\n" - ] - }, - "metadata": {}, - "output_type": "display_data", - "jetTransient": { - "display_id": null - } - }, - { - "ename": "AioRpcError", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mAioRpcError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[0;32mIn[54], line 24\u001B[0m\n\u001B[1;32m 21\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 22\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCreating calculated channel: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mcalc_channel_name\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m---> 24\u001B[0m calc_channel \u001B[38;5;241m=\u001B[39m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcalculated_channels\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcreate\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 25\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mdict\u001B[39;49m\u001B[43m(\u001B[49m\n\u001B[1;32m 26\u001B[0m \u001B[43m \u001B[49m\u001B[43mname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcalc_channel_name\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 27\u001B[0m \u001B[43m \u001B[49m\u001B[43mdescription\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43mf\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mRatio of \u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mchannel1\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m to \u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mchannel2\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 28\u001B[0m \u001B[43m \u001B[49m\u001B[43mexpression\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m$1 / $2\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# $1 and $2 refer to the channel references below\u001B[39;49;00m\n\u001B[1;32m 29\u001B[0m \u001B[43m \u001B[49m\u001B[43mexpression_channel_references\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\n\u001B[1;32m 30\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mdict\u001B[39;49m\u001B[43m(\u001B[49m\n\u001B[1;32m 31\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_reference\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m$1\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 32\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_identifier\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchannel1\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\n\u001B[1;32m 33\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 34\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;28;43mdict\u001B[39;49m\u001B[43m(\u001B[49m\n\u001B[1;32m 35\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_reference\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m$2\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 36\u001B[0m \u001B[43m \u001B[49m\u001B[43mchannel_identifier\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchannel2\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mname\u001B[49m\n\u001B[1;32m 37\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 38\u001B[0m \u001B[43m \u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 39\u001B[0m \u001B[43m \u001B[49m\u001B[43masset_ids\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m[\u001B[49m\u001B[43masset\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mid_\u001B[49m\u001B[43m]\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 40\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 41\u001B[0m \u001B[43m \u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 43\u001B[0m \u001B[38;5;28mprint\u001B[39m(calc_channel)\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:72\u001B[0m, in \u001B[0;36mgenerate_sync_api.._make_sync..sync_func\u001B[0;34m(self, *a, **kw)\u001B[0m\n\u001B[1;32m 70\u001B[0m \u001B[38;5;129m@wraps\u001B[39m(async_func)\n\u001B[1;32m 71\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21msync_func\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39ma, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkw):\n\u001B[0;32m---> 72\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_run\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mgetattr\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_async_impl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfunc_name\u001B[49m\u001B[43m)\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43ma\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkw\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/sync_wrapper.py:56\u001B[0m, in \u001B[0;36mgenerate_sync_api.._run\u001B[0;34m(self, coro)\u001B[0m\n\u001B[1;32m 54\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m_run\u001B[39m(\u001B[38;5;28mself\u001B[39m, coro):\n\u001B[1;32m 55\u001B[0m loop \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_async_impl\u001B[38;5;241m.\u001B[39mclient\u001B[38;5;241m.\u001B[39mget_asyncio_loop()\n\u001B[0;32m---> 56\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43masyncio\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrun_coroutine_threadsafe\u001B[49m\u001B[43m(\u001B[49m\u001B[43mcoro\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mloop\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mresult\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:444\u001B[0m, in \u001B[0;36mFuture.result\u001B[0;34m(self, timeout)\u001B[0m\n\u001B[1;32m 442\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m CancelledError()\n\u001B[1;32m 443\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_state \u001B[38;5;241m==\u001B[39m FINISHED:\n\u001B[0;32m--> 444\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__get_result\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 445\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 446\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mTimeoutError\u001B[39;00m()\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/concurrent/futures/_base.py:389\u001B[0m, in \u001B[0;36mFuture.__get_result\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 387\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception:\n\u001B[1;32m 388\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m--> 389\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_exception\n\u001B[1;32m 390\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n\u001B[1;32m 391\u001B[0m \u001B[38;5;66;03m# Break a reference cycle with the exception in self._exception\u001B[39;00m\n\u001B[1;32m 392\u001B[0m \u001B[38;5;28mself\u001B[39m \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/resources/calculated_channels.py:208\u001B[0m, in \u001B[0;36mCalculatedChannelsAPIAsync.create\u001B[0;34m(self, create)\u001B[0m\n\u001B[1;32m 205\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(create, \u001B[38;5;28mdict\u001B[39m):\n\u001B[1;32m 206\u001B[0m create \u001B[38;5;241m=\u001B[39m CalculatedChannelCreate\u001B[38;5;241m.\u001B[39mmodel_validate(create)\n\u001B[0;32m--> 208\u001B[0m created_calc_channel, _ \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_low_level_client\u001B[38;5;241m.\u001B[39mcreate_calculated_channel(\n\u001B[1;32m 209\u001B[0m create\u001B[38;5;241m=\u001B[39mcreate\n\u001B[1;32m 210\u001B[0m )\n\u001B[1;32m 211\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_apply_client_to_instance(created_calc_channel)\n", - "File \u001B[0;32m~/Projects/sift-clients/python/lib/sift_client/_internal/low_level_wrappers/calculated_channels.py:78\u001B[0m, in \u001B[0;36mCalculatedChannelsLowLevelClient.create_calculated_channel\u001B[0;34m(self, create)\u001B[0m\n\u001B[1;32m 74\u001B[0m \u001B[38;5;28;01masync\u001B[39;00m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mcreate_calculated_channel\u001B[39m(\n\u001B[1;32m 75\u001B[0m \u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39m, create: CalculatedChannelCreate\n\u001B[1;32m 76\u001B[0m ) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28mtuple\u001B[39m[CalculatedChannel, \u001B[38;5;28mlist\u001B[39m[Any]]:\n\u001B[1;32m 77\u001B[0m request \u001B[38;5;241m=\u001B[39m create\u001B[38;5;241m.\u001B[39mto_proto()\n\u001B[0;32m---> 78\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mawait\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_grpc_client\u001B[38;5;241m.\u001B[39mget_stub(\n\u001B[1;32m 79\u001B[0m CalculatedChannelServiceStub\n\u001B[1;32m 80\u001B[0m )\u001B[38;5;241m.\u001B[39mCreateCalculatedChannel(request)\n\u001B[1;32m 81\u001B[0m response \u001B[38;5;241m=\u001B[39m cast(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mCreateCalculatedChannelResponse\u001B[39m\u001B[38;5;124m\"\u001B[39m, response)\n\u001B[1;32m 83\u001B[0m calculated_channel \u001B[38;5;241m=\u001B[39m CalculatedChannel\u001B[38;5;241m.\u001B[39m_from_proto(response\u001B[38;5;241m.\u001B[39mcalculated_channel)\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_interceptor.py:472\u001B[0m, in \u001B[0;36m_InterceptedUnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 470\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__await__\u001B[39m(\u001B[38;5;28mself\u001B[39m):\n\u001B[1;32m 471\u001B[0m call \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_interceptors_task\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[0;32m--> 472\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01myield from\u001B[39;00m call\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__await__\u001B[39m()\n\u001B[1;32m 473\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", - "File \u001B[0;32m~/miniconda3/envs/sift-client_3_8/lib/python3.8/site-packages/grpc/aio/_call.py:327\u001B[0m, in \u001B[0;36m_UnaryResponseMixin.__await__\u001B[0;34m(self)\u001B[0m\n\u001B[1;32m 325\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m asyncio\u001B[38;5;241m.\u001B[39mCancelledError()\n\u001B[1;32m 326\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m--> 327\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m _create_rpc_error(\n\u001B[1;32m 328\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_initial_metadata,\n\u001B[1;32m 329\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_cython_call\u001B[38;5;241m.\u001B[39m_status,\n\u001B[1;32m 330\u001B[0m )\n\u001B[1;32m 331\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 332\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m response\n", - "\u001B[0;31mAioRpcError\u001B[0m: " - ] - } - ], - "execution_count": 54 + "print(calc_channel)" + ] }, { + "cell_type": "code", + "execution_count": 25, + "id": "c3be1f869e83d59d", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:41.257980Z", "start_time": "2025-10-10T21:35:07.170355Z" } }, - "cell_type": "code", - "source": [ - "# List all calculated channels for the asset\n", - "calc_channels = client.calculated_channels.list_(\n", - " asset=asset.id_,\n", - " name=calc_channel_name,\n", - " limit=10\n", - ")\n", - "\n", - "print(f\"Calculated channels for asset '{asset.name}': {len(calc_channels)}\")\n", - "for cc in calc_channels:\n", - " print(f\" - {cc.name}\")\n", - " print(f\" Expression: {cc.expression}\")\n", - " print(f\" Version: {cc.version}\")" - ], - "id": "c3be1f869e83d59d", "outputs": [ { "data": { - "text/plain": [ - "Calculated channels for asset \u001B[32m'MarsRover0'\u001B[0m: \u001B[1;36m1\u001B[0m\n" - ], "text/html": [ "
Calculated channels for asset 'MarsRover0': 1\n",
        "
\n" + ], + "text/plain": [ + "Calculated channels for asset \u001b[32m'MarsRover0'\u001b[0m: \u001b[1;36m1\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " - is_even_per_voltage\n" - ], "text/html": [ "
  - is_even_per_voltage\n",
        "
\n" + ], + "text/plain": [ + " - is_even_per_voltage\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " Expression: $\u001B[1;36m1\u001B[0m \u001B[35m/\u001B[0m $\u001B[1;36m2\u001B[0m\n" - ], "text/html": [ "
    Expression: $1 / $2\n",
        "
\n" + ], + "text/plain": [ + " Expression: $\u001b[1;36m1\u001b[0m \u001b[35m/\u001b[0m $\u001b[1;36m2\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - " Version: \u001B[1;36m1\u001B[0m\n" - ], "text/html": [ "
    Version: 1\n",
        "
\n" + ], + "text/plain": [ + " Version: \u001b[1;36m1\u001b[0m\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 25 + "source": [ + "# List all calculated channels for the asset\n", + "calc_channels = client.calculated_channels.list_(asset=asset.id_, name=calc_channel_name, limit=10)\n", + "\n", + "print(f\"Calculated channels for asset '{asset.name}': {len(calc_channels)}\")\n", + "for cc in calc_channels:\n", + " print(f\" - {cc.name}\")\n", + " print(f\" Expression: {cc.expression}\")\n", + " print(f\" Version: {cc.version}\")" + ] }, { + "cell_type": "code", + "execution_count": 26, + "id": "37b76600aedba1a1", "metadata": { "ExecuteTime": { "end_time": "2025-10-10T21:43:41.258564Z", "start_time": "2025-10-10T21:36:19.888164Z" } }, - "cell_type": "code", - "source": [ - "# Optional: Clean up resources\n", - "# Uncomment to archive the created calculated channel and rule\n", - "\n", - "if calc_channel:\n", - " calc_channel.archive()\n", - " print(f\"Archived calculated channel: {calc_channel.name}\")\n", - "\n", - "print(\"\\n✓ Example complete!\")" - ], - "id": "37b76600aedba1a1", "outputs": [ { "data": { - "text/plain": [ - "Archived calculated channel: is_even_per_voltage\n" - ], "text/html": [ "
Archived calculated channel: is_even_per_voltage\n",
        "
\n" + ], + "text/plain": [ + "Archived calculated channel: is_even_per_voltage\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "text/plain": [ - "\n", - "✓ Example complete!\n" - ], "text/html": [ "
\n",
        "✓ Example complete!\n",
        "
\n" + ], + "text/plain": [ + "\n", + "✓ Example complete!\n" ] }, - "metadata": {}, - "output_type": "display_data", "jetTransient": { "display_id": null - } + }, + "metadata": {}, + "output_type": "display_data" } ], - "execution_count": 26 + "source": [ + "# Optional: Clean up resources\n", + "# Uncomment to archive the created calculated channel and rule\n", + "\n", + "if calc_channel:\n", + " calc_channel.archive()\n", + " print(f\"Archived calculated channel: {calc_channel.name}\")\n", + "\n", + "print(\"\\n✓ Example complete!\")" + ] } ], "metadata": { From ac58bd32df5a0c511fcaed3c5a5c3ef267235bbd Mon Sep 17 00:00:00 2001 From: Alex Luck Date: Fri, 10 Oct 2025 16:35:29 -0700 Subject: [PATCH 6/6] fix rebase --- python/mkdocs.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/mkdocs.yml b/python/mkdocs.yml index f4098b10a..3c68c3564 100644 --- a/python/mkdocs.yml +++ b/python/mkdocs.yml @@ -69,8 +69,6 @@ plugins: - mkdocs-jupyter: include_source: True execute: False - - mkdocs-jupyter: - include_source: True - mkdocstrings: default_handler: python handlers: