Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
117 commits
Select commit Hold shift + click to select a range
d102363
chore: Add .aider* to .gitignore
joshuanapoli May 12, 2025
eb8aed2
docs: Add README with data model and API documentation
joshuanapoli May 12, 2025
0513e53
chore: install poetry
joshuanapoli May 12, 2025
945eb9b
chore: add black
joshuanapoli May 12, 2025
bdbe1b1
chore: add pytest
joshuanapoli May 12, 2025
22a210a
feat: Create CVec class scaffold with basic methods
joshuanapoli May 12, 2025
f39ad3c
feat: Add pandas as a project dependency
joshuanapoli May 12, 2025
0ea449b
chore: setup aider
joshuanapoli May 12, 2025
5b8a5b3
feat: Implement CVec class constructor with env var fallback.
joshuanapoli May 12, 2025
f296e53
style: Run linter on cvec.py
joshuanapoli May 12, 2025
e1974da
test: Add unit tests for the CVec constructor
joshuanapoli May 12, 2025
096d6a6
feat: Expose CVec class in src/cvec/__init__.py
joshuanapoli May 12, 2025
dd35c3d
test: Import CVec directly from package
joshuanapoli May 12, 2025
3613f7d
ci: Add GitHub Action for black and pytest checks
joshuanapoli May 12, 2025
4d468dc
build: Update CI workflow and pyproject.toml for Python 3.9-3.13 support
joshuanapoli May 12, 2025
d0cbc90
ci: Run CI workflow on multiple Python versions
joshuanapoli May 12, 2025
34f4af3
feat: Add psycopg2-binary dependency for PostgreSQL support
joshuanapoli May 12, 2025
5efaecf
docs: Add database schema documentation to README
joshuanapoli May 12, 2025
05344e7
refactor: Replace time_range with start_at and end_at parameters
joshuanapoli May 12, 2025
1c6aeb8
style: Run linter on cvec.py
joshuanapoli May 12, 2025
05f0ebd
fix: Corrected begin_at to start_at in get_spans documentation
joshuanapoli May 12, 2025
d58638c
feat: Implement get_spans from tag_data and tag_data_str.
joshuanapoli May 13, 2025
e3e582f
style: Run linter on cvec.py
joshuanapoli May 13, 2025
a541baf
docs: Clarify tag_data and tag_data_str table descriptions in README
joshuanapoli May 13, 2025
380d757
feat: Modify get_spans to only report spans within time period.
joshuanapoli May 13, 2025
b426e94
style: Apply linting to cvec.py
joshuanapoli May 13, 2025
90de5de
docs: Improve docstring for get_time_spans_where_value_changed
joshuanapoli May 13, 2025
ce499f7
feat: Allow unbounded start_at/end_at in get_spans and spans' end_at
joshuanapoli May 13, 2025
2b48944
style: Apply linter formatting to cvec.py
joshuanapoli May 13, 2025
a0f77eb
refactor: Simplify get_spans query construction with static SQL
joshuanapoli May 13, 2025
937af38
refactor: Inline where_sql in get_spans for readability
joshuanapoli May 13, 2025
a24e67b
refactor: Combine tag_data and tag_data_str queries into one SQL query
joshuanapoli May 13, 2025
cc0f2ba
style: Apply linter to cvec.py
joshuanapoli May 13, 2025
af3732e
refactor: Return numeric and string tag values as separate columns
joshuanapoli May 13, 2025
643b85a
style: Apply linter to cvec.py
joshuanapoli May 13, 2025
162bd01
feat: Add LIMIT clause to SQL query in get_spans method
joshuanapoli May 13, 2025
d9b8b3c
style: Run linter on cvec.py
joshuanapoli May 13, 2025
d2bdccb
feat: Introduce Span class and update get_spans to use it.
joshuanapoli May 13, 2025
573b5b7
refactor: Move Span class to its own module
joshuanapoli May 13, 2025
f9b95de
refactor: Simplify value assignment in fetch_timeseries_data
joshuanapoli May 13, 2025
8bc5f83
refactor: Use list comprehension for building all_points
joshuanapoli May 13, 2025
9aec426
style: Apply linter to fix code formatting issues
joshuanapoli May 13, 2025
0253771
feat: Improve span retrieval with limit and tenant handling
joshuanapoli May 13, 2025
727ab2b
feat: Upgrade to psycopg3 and update connection logic.
joshuanapoli May 13, 2025
0be9980
style: Apply linting to cvec.py
joshuanapoli May 13, 2025
6f18d33
refactor: Use named parameters in SQL queries for get_spans method
joshuanapoli May 13, 2025
6449b78
style: Apply linting to cvec.py
joshuanapoli May 13, 2025
7cc9808
refactor: Simplify database connection in CVec class
joshuanapoli May 13, 2025
434197d
perf: Improve get_spans query by joining tag_names table.
joshuanapoli May 13, 2025
1dc9306
style: Apply code formatting to cvec.py
joshuanapoli May 13, 2025
91561a2
refactor: Simplify span creation and query parameters in CVec
joshuanapoli May 13, 2025
3d13b23
refactor: Use list comprehension to build spans list in get_spans
joshuanapoli May 13, 2025
2e7b133
style: Apply code formatting with black
joshuanapoli May 13, 2025
8df38db
refactor: Remove start_at and end_at fields from Span class
joshuanapoli May 13, 2025
56e5b59
refactor: Eliminate all_points list in get_spans method
joshuanapoli May 13, 2025
daca04a
feat: Return spans in descending order, newest first
joshuanapoli May 13, 2025
d701c5b
fix: Correctly handle limit and end_at in get_spans query.
joshuanapoli May 13, 2025
da4ad18
feat: Add type hints to Span class member fields
joshuanapoli May 14, 2025
19163e9
style: Run linter on span.py
joshuanapoli May 14, 2025
ff3c0d9
feat: Add type hints to cvec.py
joshuanapoli May 14, 2025
58c55c2
style: Run linter on cvec.py
joshuanapoli May 14, 2025
293056c
refactor: Use "with" statement for db connection in get_spans
joshuanapoli May 14, 2025
d84f618
refactor: Use tuple-based rows instead of dict_row in psycopg
joshuanapoli May 14, 2025
8105e12
style: Apply linting to cvec.py
joshuanapoli May 14, 2025
454c37f
refactor: Unpack db_rows tuple directly into named variables.
joshuanapoli May 14, 2025
878aab1
style: Apply linter to cvec.py
joshuanapoli May 14, 2025
c642227
refactor: Use CTE to simplify and optimize get_spans SQL query
joshuanapoli May 14, 2025
590c4bb
fix: Resolve mypy type checking errors in tests and cvec module
joshuanapoli May 14, 2025
766b82b
chore: Remove Python 3.9 from CI matrix
joshuanapoli May 14, 2025
27a0f12
ci: Run mypy type checker in CI workflow
joshuanapoli May 14, 2025
22ef3cc
fix: Resolve mypy errors in tests by using datetime objects
joshuanapoli May 14, 2025
fdf6b12
style: Apply linter formatting to test_cvec.py
joshuanapoli May 14, 2025
2784ae4
build: Add mypy and pandas-stubs, enforce strict type checking
joshuanapoli May 14, 2025
078283c
feat: Use metric_data view in get_metric and add view definition
joshuanapoli May 14, 2025
4820b52
test: Add unit test for get_spans method in CVec class
joshuanapoli May 14, 2025
0ffdf2b
style: Apply linter to test_cvec.py
joshuanapoli May 14, 2025
fc10d71
test: Add unit test for get_spans with end_at parameter
joshuanapoli May 14, 2025
32d91cd
test: Verify psycopg query parameters in get_spans tests
joshuanapoli May 14, 2025
778918c
feat: Add unit test for get_spans with no data points
joshuanapoli May 14, 2025
a5d2d1d
test: Add unit test for get_spans with limit parameter
joshuanapoli May 14, 2025
3b8ac18
test: Remove redundant assertions in TestCVecGetSpans
joshuanapoli May 14, 2025
c86a925
feat: Implement get_metric_data to fetch metric data as DataFrame
joshuanapoli May 14, 2025
bd41ade
style: Apply linting to cvec.py
joshuanapoli May 14, 2025
0700a65
refactor: Statically include conditions in get_metric_data query
joshuanapoli May 14, 2025
f9b4ea6
test: Add unit tests for get_metric_data method
joshuanapoli May 15, 2025
569cc01
feat: Add tests for get_metric_data endpoint
joshuanapoli May 15, 2025
07a4be1
style: Apply linter to tests/test_cvec.py
joshuanapoli May 15, 2025
781ab6f
fix: Use list instead of tuple for tag_names_list in SQL query params
joshuanapoli May 15, 2025
29e0c9e
feat: implement get_tags method to fetch tags from the database
joshuanapoli May 15, 2025
83ccc21
refactor: Remove tenant from SQL queries in get_tags
joshuanapoli May 15, 2025
e6fe12c
refactor: Rename get_tags to get_metrics and update documentation
joshuanapoli May 15, 2025
0f27ba0
feat: Introduce Metric class and update get_metrics to return Metric …
joshuanapoli May 15, 2025
e07ee14
test: Add unit tests for get_metrics method in CVec class
joshuanapoli May 15, 2025
4c52bbd
style: Apply linter to tests/test_cvec.py
joshuanapoli May 15, 2025
0b3e666
feat: Add birth_at and death_at to metric_data view
joshuanapoli May 15, 2025
23a4604
refactor: Use metric_data view in get_metrics for time intervals
joshuanapoli May 15, 2025
85fc9f7
fix: Update assertions in test_get_metrics_with_interval
joshuanapoli May 15, 2025
420f76d
style: Apply linter fixes to test_cvec.py
joshuanapoli May 15, 2025
d26ea33
refactor: Simplify metric_data view creation
joshuanapoli May 15, 2025
ecb633d
docs: Clarify raw_end_at description in Span object documentation
joshuanapoli May 15, 2025
81d2891
feat: Add lint script to run black and mypy
joshuanapoli May 15, 2025
570ad68
refactor: Rename tag_name to name in Span and get_spans, update docs
joshuanapoli May 15, 2025
d737b78
refactor: Rename tag_name to name for spans and get_spans function
joshuanapoli May 15, 2025
e872c72
chore: Use lint.sh script for linting commands
joshuanapoli May 15, 2025
9285909
refactor: Rename tag_names to names in get_metric_data method
joshuanapoli May 15, 2025
3f06955
feat: Rename tag_name column to name in get_metric_data output
joshuanapoli May 15, 2025
c918602
feat: Return value_double and value_string columns in get_metric_data
joshuanapoli May 15, 2025
664bc12
style: Apply linter to fix code formatting issues
joshuanapoli May 15, 2025
d8e883a
fix: Correctly handle missing values in get_metric_data test
joshuanapoli May 15, 2025
2e5ccd3
feat: Format Span timestamps in RFC 3339 format in repr
joshuanapoli May 15, 2025
06009c4
docs: Add example usage and class documentation to README
joshuanapoli May 15, 2025
a13d8eb
chore: use ruff linter
joshuanapoli May 17, 2025
7ab7697
docs: Update README and pyproject metadata
joshuanapoli May 19, 2025
8d3e14a
docs: Complete Metrics documentation in the cvec SDK.
joshuanapoli May 19, 2025
6a11898
docs: Add documentation for get_metrics and get_metric_data functions
joshuanapoli May 19, 2025
364451b
feat: Update SDK documentation and examples, fix minor issues
joshuanapoli May 19, 2025
56f10f6
fix: psycopg requires list rather than tuple
joshuanapoli May 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .aider.conf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
lint-cmd:
- "python: scripts/lint.sh"
auto-lint: true
test-cmd: poetry run pytest
auto-test: true
read:
- README.md
59 changes: 59 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Python CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Poetry
uses: snok/install-poetry@v1
with:
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true

- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}

- name: Install dependencies
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root

- name: Install project
run: poetry install --no-interaction

- name: Ruff lint check
run: |
poetry run ruff check .

- name: Ruff format check
run: |
poetry run ruff format --check .

- name: Type check
run: |
poetry run mypy --strict .

- name: Run tests
run: |
poetry run pytest
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,4 @@ cython_debug/

# PyPI configuration file
.pypirc
.aider*
150 changes: 148 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,148 @@
# cvec-python
CVector SDK for Python
# CVec Client Library

The "cvec" package is the Python SDK for CVector Energy.

# Getting Started

## Installation

Assuming that you have a supported version of Python installed, you can first create a venv with:

```
python -m venv .venv
```

Then, activate the venv:

```
. .venv/bin/activate
```

Then, you can install cvec from PyPI with:

```
pip install cvec
```

## Using cvec

Import the cvec package. We will also use the datetime module.

```
import cvec
from datetime import datetime
```

Construct the CVec client. The host, tenant, and api_key can be given through parameters to the constructor or from the environment variables CVEC_HOST, CVEC_TENANT, and CVEC_API_KEY:

```
cvec = cvec.CVec()
```

### Spans

A span is a period of interest, such as an experiment, a baseline recording session, or an alarm. The initial state of a Span is implicitly defined by a period where a given metric has a constant value.

The newest span for a metric does not have an end time, since it has not ended yet (or has not ended by the finish of the queried period).

To get the spans on `my_tag_name` since 2025-05-14 10am, run:

```
for span in cvec.get_spans("mygroup/myedge/mode", start_at=datetime(2025, 5, 14, 10, 0, 0)):
print("%s\t%s" % (span.value, span.raw_start_at))
```

The output will be like:

```
offline 2025-05-19 16:28:02.130000+00:00
starting 2025-05-19 16:28:01.107000+00:00
running 2025-05-19 15:29:28.795000+00:00
stopping 2025-05-19 15:29:27.788000+00:00
offline 2025-05-19 14:14:43.752000+00:00
```

### Metrics

A metric is a named set of time-series data points pertaining to a particular resource (for example, the value reported by a sensor). Metrics can have numeric or string values. Boolean values are mapped to 0 and 1. The get_metrics function returns a list of metric metadata.

To get all of the metrics that changed value at 10am on 2025-05-14, run:

```
for item in cvec.get_metrics(start_at=datetime(2025, 5, 14, 10, 0, 0), end_at=datetime(2025, 5, 14, 11, 0, 0)):
print(item.name)
```

Example output:

```
mygroup/myedge/compressor01/status
mygroup/myedge/compressor01/interlocks/emergency_stop
mygroup/myedge/compressor01/stage1/pressure_out/psig
mygroup/myedge/compressor01/stage1/temp_out/c
mygroup/myedge/compressor01/stage2/pressure_out/psig
mygroup/myedge/compressor01/stage2/temp_out/c
mygroup/myedge/compressor01/motor/current/a
mygroup/myedge/compressor01/motor/power_kw
```

### Metric Data

The main content for a metric is a set of points where the metric value changed. These are returned as a Pandas Dataframe with columns for name, time, value_double, value_string.

To get all of the value changes for all metrics at 10am on 2025-05-14, run:

```
cvec.get_metric_data(start_at=datetime(2025, 5, 14, 10, 0, 0), end_at=datetime(2025, 5, 14, 11, 0, 0))
```

Example output:

```
name time value_double value_string
0 mygroup/myedge/mode 2025-05-14 10:10:41.949000+00:00 24.900000 starting
1 mygroup/myedge/compressor01/interlocks/emergency_stop 2025-05-14 10:27:24.899000+00:00 0.0000000 None
2 mygroup/myedge/compressor01/stage1/pressure_out/psig 2025-05-14 10:43:38.282000+00:00 123.50000 None
3 mygroup/myedge/compressor01/stage1/temp_out/c 2025-05-14 10:10:41.948000+00:00 24.900000 None
4 mygroup/myedge/compressor01/motor/current/a 2025-05-14 10:27:24.897000+00:00 12.000000 None
... ... ... ... ...
46253 mygroup/myedge/compressor01/stage1/temp_out/c 2025-05-14 10:59:55.725000+00:00 25.300000 None
46254 mygroup/myedge/compressor01/stage2/pressure_out/psig 2025-05-14 10:59:56.736000+00:00 250.00000 None
46255 mygroup/myedge/compressor01/stage2/temp_out/c 2025-05-14 10:59:57.746000+00:00 12.700000 None
46256 mygroup/myedge/compressor01/motor/current/a 2025-05-14 10:59:58.752000+00:00 11.300000 None
46257 mygroup/myedge/compressor01/motor/power_kw 2025-05-14 10:59:59.760000+00:00 523.40000 None

[46257 rows x 4 columns]
```

# CVec Class

The SDK provides an API client class named `CVec` with the following functions.

## `__init__(?host, ?tenant, ?api_key, ?default_start_at, ?default_end_at)`

Setup the SDK with the given host and API Key. The host and API key are loaded from environment variables CVEC_HOST, CVEC_TENANT, CVEC_API_KEY, if they are not given as arguments to the constructor. The `default_start_at` and `default_end_at` can provide a default query time interval for API methods.

## `get_spans(name, ?start_at, ?end_at, ?limit)`

Return time spans for a metric. Spans are generated from value changes that occur after `start_at` (if specified) and before `end_at` (if specified).
If `start_at` is `None` (e.g., not provided as an argument and no class default `default_start_at` is set), the query for value changes is unbounded at the start. Similarly, if `end_at` is `None`, the query is unbounded at the end.

Each `Span` object in the returned list represents a period where the metric's value is constant and has the following attributes:
- `value`: The metric's value during the span.
- `name`: The name of the metric.
- `raw_start_at`: The timestamp of the value change that initiated this span's value. This will be greater than or equal to the query's `start_at` if one was specified.
- `raw_end_at`: The timestamp marking the end of this span's constant value. For the newest span, the value is `None`. For other spans, it's the raw_start_at of the immediately newer data point, which is next span in the list.
- `id`: Currently `None`. In a future version of the SDK, this will be the span's unique identifier.
- `metadata`: Currently `None`. In a future version, this can be used to store annotations or other metadata related to the span.

Returns a list of `Span` objects, sorted in descending chronological order (newest span first).
If no relevant value changes are found, an empty list is returned.

## `get_metric_data(?names, ?start_at, ?end_at)`

Return all data-points within a given [`start_at`, `end_at`) interval, optionally selecting a given list of metric names. The return value is a Pandas DataFrame with four columns: name, time, value_double, value_string. One row is returned for each metric value transition.

## `get_metrics(?start_at, ?end_at)`

Return a list of metrics that had at least one transition in the given [`start_at`, `end_at`) interval. All metrics are returned if no `start_at` and `end_at` are given.
Loading