Skip to main content

Micantis API Wrapper

A lightweight Python wrapper for interacting with the Micantis API plus some helpful utilities.
Built for ease of use, fast prototyping, and clean integration into data workflows.


🚀 Features

  • Authenticate and connect to the Micantis API service
  • Download and parse CSV, binary, and Parquet data into pandas DataFrames
  • Parquet support for efficient data storage with embedded metadata
  • Filter, search, and retrieve metadata
  • Create and soft-delete cells, optionally assigning existing data files during creation
  • Stitch and clean data sets programmatically
  • Track data changes with the changelog endpoint
  • Find duplicate files in your data library
  • Upload artifacts from Python script executions
  • Monitor and manage async background jobs with built-in polling
  • All methods support a timeout parameter for fine-grained control
  • Automatic session recovery — expired tokens are re-authenticated transparently

⚠️ Important

This package is designed for authenticated Micantis customers only.
If you are not a Micantis customer, the API wrapper and utilities in this package will not work for you.

For more information on accessing the Micantis API, please contact us at info@micantis.io.


📦 Installation

pip install micantis

Optional: Parquet Support

For parquet file downloads and metadata extraction, install with parquet support:

pip install micantis[parquet]

Or install pyarrow separately:

pip install pyarrow

💻 Examples

Import functions

import pandas as pd
from micantis import MicantisAPI

Initialize API

# Option 1 - login with username and password
service_url = 'your service url'
username = 'your username'
password = 'your password'

api = MicantisAPI(service_url=service_url, username=username, password=password)
# Option 2 - login in with Microsoft Entra ID
SERVICE = 'your service url'
CLIENT_ID = 'your client id'
AUTHORITY = 'https://login.microsoftonline.com/organizations'
SCOPES = ['your scopes']

api = MicantisAPI(service_url=SERVICE, client_id=CLIENT_ID, authority=AUTHORITY, scopes=SCOPES)
# Option 2b - login with Okta single sign-on
# Sign-in opens in the browser; the redirect URI (default
# http://localhost:8765/login/callback) must be registered as a sign-in
# redirect URI on the Okta application.
SERVICE = 'your service url'
OKTA_DOMAIN = 'yourcompany.okta.com'
OKTA_CLIENT_ID = 'your okta client id'

api = MicantisAPI(service_url=SERVICE, okta_domain=OKTA_DOMAIN, okta_client_id=OKTA_CLIENT_ID)
# Option 3 - Use pre-existing token (for containerized apps)
service_url = 'your service url'
token = 'your bearer token'

api = MicantisAPI(service_url=service_url, token=token)
# No need to call authenticate() when using a token
# Option 4 - Use environment variables (recommended for containers/CI/CD)
# Set these environment variables:
# - WORKBOOK_API_URL: your service URL
# - WORKBOOK_TOKEN: your bearer token

api = MicantisAPI()  # Will automatically use environment variables
# No need to call authenticate() when using a token
# Option 5 - Externally-managed tokens (web apps holding per-user tokens)
# Provide a zero-argument callable that always returns a currently-valid
# bearer token. It is consulted before every request (and on 401 retry),
# so your app owns the refresh logic — e.g. reading the signed-in user's
# token from Azure App Service / Container Apps built-in authentication.
service_url = 'your service url'

api = MicantisAPI(service_url=service_url, token_provider=get_current_user_token)
# No need to call authenticate() when using a token provider

Authenticate API

api.authenticate()

Note: When using a pre-existing token (Option 3 or 4) or a token provider (Option 5), you don't need to call authenticate() as the token is already configured.

Who am I?

me = api.get_whoami()
# {'username': 'jane.doe@example.com', 'displayName': 'Jane Doe', 'email': ...,
#  'roles': ['Analyst'], 'accessGroups': [{'id': 3, 'name': 'PRC'}],
#  'defaultAccessGroupId': 3, 'unrestrictedAccess': False}

Returns the identity the API resolves for your credentials, including the access groups that scope your data visibility. Handy for "signed in as ..." banners and for discovering which labs/groups you can query.

Download Data Table Summary

Optional parameters

  • search: Search string (same syntax as the Micantis WebApp)
  • barcode: Filter by barcode
  • limit: Number of results to return (default: 500)
  • show_ignored: Include soft-deleted files (default: True)
  • min_start_date: Only return results whose test started on or after this date (ISO format)
  • max_start_date: Only return results whose test started on or before this date (ISO format)
  • min_end_date: Only return results whose test ended on or after this date (ISO format)
  • max_end_date: Only return results whose test ended on or before this date (ISO format)
  • station: Filter by test station name
  • channel: Filter by channel
  • cell_test_name: Filter by cell test name
  • data_kind: Filter by data type (e.g. "CycleTesterData", "StitchedData", "PotentiostatData", "FileData")
# Basic search
table = api.get_data_table(search="your search string", limit=100)

# Filter by start date range
table = api.get_data_table(min_start_date="2025-01-01", max_start_date="2025-06-01")

# Filter by end date range
table = api.get_data_table(min_end_date="2025-01-01", max_end_date="2025-06-01")

# Filter by station and data type
table = api.get_data_table(station="your station name", data_kind="CycleTesterData")

# Filter by cell test name
table = api.get_data_table(cell_test_name="your cell test name")

# Combine multiple filters
table = api.get_data_table(
    min_start_date="2025-01-01",
    max_start_date="2025-12-31",
    data_kind="CycleTesterData",
    search="your search string",
    limit=100
)

Download Binary Files

# Download single file

file_id = 'File ID obtained from data table, id column'
df = api.download_binary_file(id)
# Download many files using list of files from the table

file_id_list = table['id'].to_list()
data = []

for id in file_id_list:
    df = api.download_csv_file(id)
    data.append(df)

all_data = pd.concat(data)

Download CSV Files

# Download single file

file_id = 'File ID obtained from data table, id column'
df = api.download_csv_file(id)
# Download multiple files

id_list = table['id'].to_list()
data = []

for id in id_list:
    df = api.download_csv_file(id)
    data.append(df)

all_data = pd.concat(data)

Download Parquet Files

Download cycle tester data as Apache Parquet files for efficient analysis. Parquet files are smaller, faster, and include embedded metadata.

Optional parameters

  • cycle_ranges: Filter by cycle index (see examples below)
  • test_time_start: Filter by test time start (seconds from test start)
  • test_time_end: Filter by test time end (seconds from test start)
  • line_number_start: Filter by line number start
  • line_number_end: Filter by line number end
  • include_auxiliary_data: Include auxiliary channels like temperature (default: True)
  • output_path: Custom file path (default: uses cell_data_id as filename)
  • return_type: What to return - 'dataframe' (default), 'path', or 'bytes'

Return Type Options

  • 'dataframe' (default): Saves file and returns pandas DataFrame - best for immediate analysis
  • 'dict': Saves file and returns dict with data, metadata, and cycle_summaries - best when you need metadata (requires pyarrow)
  • 'path': Saves file and returns path string - best for large files or batch processing
  • 'bytes': Returns raw bytes without saving - best for direct cloud uploads (Databricks, Azure Blob, S3)
# Download and get DataFrame (default)
file_id = 'File ID obtained from data table, id column'
df = api.download_parquet_file(file_id)
# Get data + metadata in one call
result = api.download_parquet_file(file_id, return_type='dict')

df = result['data']                    # Cycle test data
metadata = result['metadata']          # Cell metadata (name, barcode, timestamps, etc.)
cycle_summaries = result['cycle_summaries']  # Per-cycle summary statistics
# Save file and get path (memory efficient for large files)
path = api.download_parquet_file(file_id, return_type='path')

# Later, read when needed
df = pd.read_parquet(path)
# Get raw bytes for direct cloud upload (no local file)
parquet_bytes = api.download_parquet_file(file_id, return_type='bytes')

# Upload to Azure Blob Storage
blob_client.upload_blob(name='test_data.parquet', data=parquet_bytes)

# Or read directly into DataFrame
import io
df = pd.read_parquet(io.BytesIO(parquet_bytes))

Cycle Range Filtering

Filter data by specific cycles or cycle ranges using the cycle_ranges parameter.

# Download only cycles 1-10
df = api.download_parquet_file(
    file_id,
    cycle_ranges=[{"RangeStart": 1, "RangeEnd": 10}]
)
# Download last 5 cycles
df = api.download_parquet_file(
    file_id,
    cycle_ranges=[{
        "RangeStart": 5,
        "IsStartFromBack": True,
        "RangeEnd": 1,
        "IsEndFromBack": True
    }]
)
# Download specific cycles (1, 5, 10, 50)
df = api.download_parquet_file(
    file_id,
    cycle_ranges=[
        {"Single": 1},
        {"Single": 5},
        {"Single": 10},
        {"Single": 50}
    ]
)
# Download first hour of data
df = api.download_parquet_file(
    file_id,
    test_time_start=0,
    test_time_end=3600
)

Extract Metadata from Parquet Files

Parquet files contain embedded metadata including cell info, timestamps, cycle counts, and per-cycle summaries. Extract this metadata using unpack_parquet() (requires pyarrow).

# From a saved file
result = api.unpack_parquet('file.parquet')

df = result['data']                    # Cycle test data
metadata = result['metadata']          # Cell metadata (name, barcode, timestamps, etc.)
cycle_summaries = result['cycle_summaries']  # Per-cycle summary statistics
# From bytes (no file needed)
parquet_bytes = api.download_parquet_file(file_id, return_type='bytes')
result = api.unpack_parquet(parquet_bytes)

df = result['data']
metadata = result['metadata']
cycle_summaries = result['cycle_summaries']
# Extract and save metadata as CSV files for easy viewing
result = api.unpack_parquet('file.parquet', save_metadata=True)

# Creates:
# - file_metadata.csv
# - file_cycle_summaries.csv
# Batch processing: Download multiple files without loading into memory
file_ids = table['id'].head(10).to_list()
paths = []

for file_id in file_ids:
    path = api.download_parquet_file(file_id, return_type='path')
    paths.append(path)

# Later, process files one at a time (memory efficient)
for path in paths:
    result = api.unpack_parquet(path)
    df = result['data']
    # Process df...

Cells Table

Create a Cell

Create a CellTest (the battery object), optionally assigning existing CellData files during creation.

# Empty cell
created = api.create_cell(name="New Cell")

# Cell with existing data files
created = api.create_cell(
    name="New Cell",
    cell_data_ids=["cell-data-guid-1", "cell-data-guid-2"],
)
print(created["id"])

The name is trimmed by the server, must be unique among live cells, and may contain only letters, digits, spaces, _, -, ., and parentheses. All supplied CellData must be visible to the caller and belong to the caller's default access group; if any file cannot be assigned, nothing is created or moved.

Supplying a CellData file that already belongs to another cell moves it. Check created["reassignments"] after every successful call. Each entry contains cellDataId, originalCellId, and originalCellName, so the prior assignment can be reported and restored if needed.

Delete a Cell

Soft-delete an empty CellTest by ID:

deleted = api.delete_cell("cell-test-guid")
if deleted is not True:
    raise RuntimeError("The cell was not deleted; check the warning printed above")

The cell remains recoverable and its name becomes available for reuse. Deletion is refused while any active or archived CellData file remains assigned; move or delete those files first. Unlike archive_data(), which toggles a CellData record's archived state, delete_cell() is a one-way soft delete recovered through the Recycle Bin. The caller needs both Data_API and Data_Delete. A repeated call returns not found because deleted cells are hidden from normal API queries.

Download Cell ID Information

Retrieve a list of cell names and GUIDs from the Micantis database with flexible filtering options.

Optional parameters

  • search: Search string (same syntax as the Micantis WebApp)
  • barcode: Search for a specific barcode
  • limit: Number of results to return (default: 500)
  • min_date: Only return results after this date
  • max_date: Only return results before this date
  • show_ignored: Include soft-deleted files (default: True)
search = "*NPD*"
cells_df = api.get_cells_list(search=search)
cells_df.head()

Download Cell Metadata

Fetch per-cell metadata and return a clean, wide-format DataFrame.

Parameters:

  • cell_ids: List[str]
    List of cell test GUIDs (required)

  • metadata: List[str] (optional)
    List of metadata names (e.g., "OCV (V)") or IDs.
    If omitted, all non-image metadata will be returned by default.

  • return_images: bool (optional)
    If True, includes image metadata fields. Default is False.


📘 Examples

# Example 1: Get all non-image metadata for a list of cells
cell_ids = cells_df["id"].to_list()
cell_metadata_df = api.get_cell_metadata(cell_ids=cell_ids)
# Example 2: Get specific metadata fields by name
cell_metadata_df = api.get_cell_metadata(
    cell_ids=cell_ids,
    metadata=["Cell width", "Cell height"],
    return_images=False
)
# Merge cell metadata table with cell names to get clean dataframe
# Merge id with Cell Name (as last column)
id_to_name = dict(zip(cells_df['id'], cells_df['name']))
cells_metadata_df['cell_name'] = cells_metadata_df['id'].map(id_to_name)
cells_metadata_df.head()

Specifications Table

Download Specifications List

Retrieve specifications with their associated user properties.

# Get all specifications with their user properties
specs_df = api.get_specifications_table()
specs_df.head()

Test Management

Download Test Requests List

Retrieve test request data with flexible date filtering.

Optional parameters

  • since: Date string in various formats (defaults to January 1, 2020 if not provided)
    • Full month names: "May 1, 2025", "January 15, 2024"
    • ISO format: "2025-05-01" or "25-05-01"
# Get all test requests (defaults to since 2020-01-01)
test_requests = api.get_test_request_list()

# Get test requests since a specific date using month name
test_requests = api.get_test_request_list(since="May 1, 2024")

# Get test requests using ISO format
test_requests = api.get_test_request_list(since="2024-05-01")

Download Failed Test Requests

Retrieve only failed test requests with the same date filtering options.

# Get failed test requests since a specific date
failed_requests = api.get_failed_test_requests(since="January 1, 2024")
failed_requests.head()

Get Individual Test Request Details

Retrieve full details for a specific test request by ID.

New Feature: Multiple output format options for better data analysis!

Format Options

  • return_format='dict': Raw dictionary (default, backwards compatible)
  • return_format='dataframes': Returns 3 DataFrames - summary, tests, and status_log ⭐ Recommended
  • return_format='flat': Single-row DataFrame with basic info
# Option 1: Dictionary format (default, backwards compatible)
request_id = "your-test-request-guid"
test_details = api.get_test_request(request_id)

# Option 2: DataFrames format (recommended for analysis) ⭐
test_details = api.get_test_request(request_id, return_format='dataframes')
print(test_details['summary'])      # Basic request information
print(test_details['tests'])        # All requested tests
print(test_details['status_log'])   # Status change history

# Option 3: Flat DataFrame (best for combining multiple requests)
test_details = api.get_test_request(request_id, return_format='flat')

Batch Processing Multiple Requests

# Get summaries for multiple test requests
request_ids = test_requests['id'].head(10).to_list()

all_summaries = []
for req_id in request_ids:
    summary = api.get_test_request(req_id, return_format='flat')
    all_summaries.append(summary)

# Combine into single DataFrame
combined_df = pd.concat(all_summaries, ignore_index=True)
print(f"Retrieved {len(combined_df)} test requests")
combined_df.head()

Get Test Request Member Cells

Retrieve the actual cells linked to a test request. Note that the tests array from get_test_request() is the test plan (names and quantities) — it contains no cell IDs.

# DataFrame with one row per member cell (default)
cells_df = api.get_test_request_cells(request_id)
cells_df.head()  # columns: id, name, updated, cycleCount, hasGraphData

# Raw list of dicts
cells = api.get_test_request_cells(request_id, return_format='list')
# Use the cell IDs directly — e.g. fetch metadata for every cell in the request
cell_ids = cells_df['id'].to_list()
metadata_df = api.get_cell_metadata(cell_ids=cell_ids, metadata=["Cell height"])

Write Cell Metadata

Micantis lets you programmatically assign or update metadata for each cell using either:

  • the built-in field "name" (renames the cell) or "dataSourceKey"
  • the human-readable field name of a user-defined property (e.g., "Technician", "Weight (g)")
  • or the internal propertyDefinitionId (UUID)

Per-entity atomic: all changes targeting a single cell commit or rollback together. If any change for a cell fails, none of that cell's changes persist; other cells are unaffected. The call returns a BatchUpdateResult:

  • result.success — True if every cell committed
  • result.errors — list of {itemId, error} dicts for the cells whose changes were rolled back
  • if result: — truthy iff full success (use .success or truthiness, not result == True)

📘 Examples

# Example 1: Rename a cell and update its dataSourceKey + a user property
changes = [
    {"id": "your-cell-test-guid-here", "field": "name", "value": "A-EVE-15P-Cell-04"},
    {"id": "your-cell-test-guid-here", "field": "dataSourceKey", "value": "Formation"},
    {"id": "your-cell-test-guid-here", "field": "Technician", "value": "Mykela"},
    {"id": "your-cell-test-guid-here", "field": "Weight (g)", "value": 98.7},
]

result = api.write_cell_metadata(changes=changes)
if not result:
    for e in result.errors:
        print(f"{e['itemId']}: {e['error']}")

# Verify the changes
api.get_cell_metadata(cell_ids=["your-cell-test-guid-here"], metadata=['Weight (g)', 'Technician'])
# Example 2: Update using propertyDefinitionId (advanced)
changes = [
    {
        "id": "your-cell-test-guid-here",
        "propertyDefinitionId": "your-property-definition-guid",
        "value": 98.7
    }
]

result = api.write_cell_metadata(changes=changes)
assert result.success, result.errors

Rename rules: CellTest names must be unique and may only contain letters, digits, and _ - . ( ) space. CellData names must be unique; renaming a CellData also auto-updates the owning CellTest's DataSourceKey.

Write Data Metadata

Assign or update metadata on a data set (CellData record), the same way as cells, using either:

  • the built-in field "name" (renames the data set) or "dataSourceKey"
  • the human-readable field name of a user-defined property (e.g., "Active Cycle Test?")
  • or the internal propertyDefinitionId (UUID)

User-defined property names are resolved against the data-set metadata definitions, which you can list with api.list_data_metadata_definitions().

Per-entity atomic: all changes targeting a single data set commit or rollback together; other data sets are unaffected. Returns a BatchUpdateResult with .success and .errors, identical to write_cell_metadata.

📘 Examples

# Example 1: Set a user-defined property on specific data sets
changes = [
    {"id": "your-cell-data-guid-here", "field": "Active Cycle Test?", "value": True},
]

result = api.write_data_metadata(changes=changes)
if not result:
    for e in result.errors:
        print(f"{e['itemId']}: {e['error']}")
# Example 2: Rename a data set and update its dataSourceKey
changes = [
    {"id": "your-cell-data-guid-here", "field": "name", "value": "Formation_Run_42"},
    {"id": "your-cell-data-guid-here", "field": "dataSourceKey", "value": "Formation"},
]

result = api.write_data_metadata(changes=changes)
assert result.success, result.errors
# Example 3: Update using propertyDefinitionId (advanced)
changes = [
    {
        "id": "your-cell-data-guid-here",
        "propertyDefinitionId": "your-property-definition-guid",
        "value": "true"
    }
]

result = api.write_data_metadata(changes=changes)
assert result.success, result.errors

Stitch Data

Combine multiple data sets into a single stitched data set. This is useful for creating continuous test data from multiple separate test runs.

Parameters

  • name: str (required) Name for the stitched data set

  • cell_data_ids: List[str] (required) List of cell data GUIDs to stitch together

  • increment_cycle_number: bool (optional) Whether to increment cycle numbers when stitching. Default is False.

  • advanced_mode: bool (optional) Advanced mode for manual ordering of data sets. Default is False.

  • archive_source_data: bool (optional) Archive (soft delete) the source data sets after stitching. Default is False.

  • id: str (optional) Optional ID for updating an existing stitched data set. Leave None to create new.

  • allow_async: bool (optional) If True, runs asynchronously and returns job ID. If False, waits for completion. Default is False.

Returns

  • If allow_async=False: Dictionary with 'stitched_data_id'
  • If allow_async=True: Dictionary with 'job_id'

📘 Examples

# Example 1: Stitch multiple test runs together
cell_data_ids = ["guid1", "guid2", "guid3"]

result = api.stitch_data(
    name="Combined Test Data",
    cell_data_ids=cell_data_ids,
    increment_cycle_number=True
)

print(f"Stitched data ID: {result['stitched_data_id']}")
# Example 2: Stitch and archive source data
result = api.stitch_data(
    name="Complete Test Sequence",
    cell_data_ids=cell_data_ids,
    increment_cycle_number=True,
    archive_source_data=True  # Source files will be soft-deleted
)

# Download the stitched result
stitched_df = api.download_parquet_file(result['stitched_data_id'])
# Example 3: Async mode for large data sets
result = api.stitch_data(
    name="Large Combined Dataset",
    cell_data_ids=large_cell_data_list,
    allow_async=True
)

# Poll until complete, then get the stitched data ID
stitched_id = api.wait_for_job(result['job_id'])
print(f"Stitched data ID: {stitched_id}")

Archive Data

Archive (soft delete) data sets. Archived data is hidden from the default list view but not permanently deleted and can be unarchived.

Note: The archive_data() method toggles the archive status - calling it on an archived file will unarchive it.

Parameters

  • cell_data_id: str (required) Cell data GUID to archive/unarchive

Returns

  • Dictionary with 'id' and 'archived' (bool indicating new state)

📘 Examples

# Example 1: Archive a single data set
result = api.archive_data(cell_data_id="your-guid-here")
print(f"File archived: {result['archived']}")  # True if now archived
# Example 2: Archive multiple data sets
cell_data_ids = ["guid1", "guid2", "guid3"]

for cell_id in cell_data_ids:
    result = api.archive_data(cell_id)
    print(f"Archived {cell_id}: {result['archived']}")
# Example 3: Unarchive by calling again
result = api.archive_data(cell_data_id="your-guid-here")
print(f"File archived: {result['archived']}")  # False if now unarchived
# Example 4: Combined workflow - stitch and archive
# Stitch data with automatic archiving
result = api.stitch_data(
    name="Combined Data",
    cell_data_ids=cell_ids,
    archive_source_data=True  # Automatically archives source files
)

# Or manually archive after stitching
result = api.stitch_data(name="Combined Data", cell_data_ids=cell_ids)
for cell_id in cell_ids:
    api.archive_data(cell_id)

Download CSV (Graph Request)

Download time-series data as a CSV file using a graph request definition. Useful for exporting specific channels or time windows from one or more data sets.

Parameters

  • graph_request: dict (required) Graph request payload specifying which data sets and axes to export
  • output_path: str (optional) Path to save the CSV file. Defaults to 'download.csv'
  • return_type: str (optional) 'dataframe' (default), 'path', or 'bytes'

Return Type Options

  • 'dataframe' (default): Saves file and returns pandas DataFrame
  • 'path': Saves file and returns path string
  • 'bytes': Returns raw bytes without saving — best for cloud uploads

📘 Examples

# Download as DataFrame (default)
graph_request = {
    "items": [{"id": "your-file-guid", "yAxis": 0, "xAxis": 0}],
    "xMin": None,
    "xMax": None,
}

df = api.download_csv(graph_request=graph_request)
# Save to a specific path
path = api.download_csv(
    graph_request=graph_request,
    output_path="my_data.csv",
    return_type='path'
)
# Get raw bytes for cloud upload
csv_bytes = api.download_csv(graph_request=graph_request, return_type='bytes')
blob_client.upload_blob(name='data.csv', data=csv_bytes)

Clean Data

Re-process one or more data sets using a supported cleaning mode. Returns the IDs of the newly created cleaned data sets.

Note: Data Cleaning is available in version 2.17+, expected to release end of March 2026. Please contact Micantis with questions about upgrading your system.

Parameters

  • source_ids: List[str] (required) List of cell data GUIDs to clean
  • mode: str (optional) Cleaning mode. One of 'CycleAutoFixup' (default), 'FilterCycles', 'Parametric', or 'MetadataEdit'. Auto-set to 'Parametric' when actions is provided.
  • actions: list (optional) List of Parametric actions built with api.remove_steps(), api.downsample_timesteps(), api.smooth_timesteps(), api.compact_line_numbers(), api.modify_step(), api.bulk_modify(), api.edit_logger_step(), and/or api.shift_time(). Auto-sets mode to 'Parametric'.
  • filter_cycles_definition: dict (optional) Required when mode='FilterCycles'
  • allow_async: bool (optional) If True, runs asynchronously and returns a job ID. Default is False
  • timeout: int (optional) Request timeout in seconds. Default is 60

Action Builders

All action builders are static methods on MicantisAPI — call them as api.remove_steps(...), api.downsample_timesteps(...), and so on.

api.remove_steps(lines, cycles, step_indices, name, renumber_line_numbers=False) — Remove timesteps by line number, cycle index, and/or step index. Ranges are (from, to) tuples (inclusive). Set renumber_line_numbers=True to compact the surviving rows to contiguous 1-based line numbers. The default remains False for compatibility with existing scripts.

api.downsample_timesteps(minimum_interval_seconds, keep_every_nth, lines, cycles, step_indices, test_time_start_seconds, test_time_end_seconds, name, renumber_line_numbers=True) — Thin timesteps in the selected region. Pass exactly one of minimum_interval_seconds (positive) or keep_every_nth (integer of at least 2). Select by line/cycle/step ranges and/or inclusive test-time bounds; omit all selectors to process the entire data set. Downsampling compacts surviving rows to contiguous 1-based line numbers by default.

api.compact_line_numbers(name=None) — Explicitly renumber every surviving timestep contiguously from 1. Use it after one or more row-removing actions when compaction should occur at a separate point in the action chain. Downsampling still compacts automatically by default, and remove_steps(..., renumber_line_numbers=True) remains available.

api.smooth_timesteps(window_rows, window_seconds, fields, column_indices, lines, cycles, step_indices, test_time_start_seconds, test_time_end_seconds, name, method="movingAverage") — Replace each selected value with a centered moving average. Pass exactly one of window_rows (odd, at least 3) or window_seconds (positive), and at least one target: fields ("voltage" and/or "current", cycle-tester only) and/or column_indices (0-based data columns: auxiliary channels on cycle-tester sources, ImportDefinition columns on data logger sources). Rows are never removed and line numbers, times, and cycle/step fields are unchanged. Windows restart at cycle/step transitions and at the edges of the selected region. Place a smooth action before any downsample action.

api.modify_step(line, name, voltage, current, charge_capacity, discharge_capacity, charge_energy, discharge_energy, cycle, step_kind, step_index) — Override specific values on a single timestep.

api.bulk_modify(lines, name, voltage, current, charge_capacity, discharge_capacity, charge_energy, discharge_energy, cycle, step_kind, step_index) — Override specific values on all timesteps within the given line number ranges. Same fields as modify_step but applied to (from, to) ranges instead of a single line. Ideal for bulk cycle number reassignment.

Returns

  • If allow_async=False: Dictionary with 'cleaned_data_ids'
  • If allow_async=True: Dictionary with 'job_id'

📘 Examples

# Example 1: Recompute cycle boundaries (most common)
result = api.clean_data(
    source_ids=["your-guid-here"],
    mode='CycleAutoFixup'
)
print(f"Cleaned data IDs: {result['cleaned_data_ids']}")
# Example 2: Remove non-nominal cycles
result = api.clean_data(
    source_ids=["your-guid-here"],
    mode='FilterCycles',
    filter_cycles_definition={}
)
# Example 3: Remove specific timesteps by line number

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.remove_steps(lines=[(1, 1), (5, 10)], name="Remove bad rows"),
    ]
)
# Example 4: Remove by cycle range

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.remove_steps(cycles=[(1, 3)], name="Remove first 3 cycles"),
    ]
)
# Example 5: Thin a dense region to no more than one retained point per second

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.downsample_timesteps(
            minimum_interval_seconds=1.0,
            lines=[(25000, 90000)],
            name="Thin noisy region",
        ),
    ]
)
# Example 6: Keep every 10th timestep across the full data set

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[api.downsample_timesteps(keep_every_nth=10)]
)
# Example 7: Smooth noisy voltage with a 5-row moving average, then thin the result

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.smooth_timesteps(window_rows=5, fields=["voltage"], name="Denoise voltage"),
        api.downsample_timesteps(keep_every_nth=10),
    ]
)
# Example 8: Modify a timestep's voltage and capacity

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.modify_step(line=42, voltage=3.7, discharge_capacity=1.2),
    ]
)
# Example 9: Remove rows, explicitly compact, then modify using the new numbering

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.remove_steps(lines=[(1, 1)]),
        api.compact_line_numbers(name="Make line numbers contiguous"),
        api.modify_step(line=5, voltage=3.7),
    ]
)
# Example 10: Bulk-reassign cycle numbers

result = api.clean_data(
    source_ids=["your-guid-here"],
    actions=[
        api.bulk_modify(lines=[(1, 5000)], cycle=0),
        api.bulk_modify(lines=[(5001, 12340)], cycle=1),
        api.bulk_modify(lines=[(12341, 18700)], cycle=2),
    ]
)
# Example 11: Async mode for large data sets
result = api.clean_data(
    source_ids=["your-guid-here"],
    mode='CycleAutoFixup',
    allow_async=True
)

# Poll until complete, then get the cleaned data IDs
cleaned_ids = api.wait_for_job(result['job_id'])
print(f"Cleaned data IDs: {cleaned_ids}")

Job Management

Monitor and control background jobs created by async operations (stitch_data, clean_data).

Polls a job until it finishes and returns the result in one call.

Parameters

  • job_id: str (required) — GUID returned by an async operation
  • poll_interval: int (optional) — seconds between status checks (default: 2)
  • timeout: int (optional) — maximum seconds to wait before giving up (default: 300)
result = api.stitch_data(name="My Stitch", cell_data_ids=[...], allow_async=True)
stitched_id = api.wait_for_job(result['job_id'])

get_job_status — check status without blocking

Returns the current status without waiting.

status = api.get_job_status(job_id)
# {
#   'id': '...',
#   'status': 'Running',   # Created | Running | Completed | Failed | Cancelled
#   'progress': 42,        # 0–100
#   'errorMessage': None
# }
print(f"Progress: {status['progress']}%")

get_job_result — fetch the result of a completed job

Returns the same value as wait_for_job once the job has finished. Returns None with a warning if the job is still running.

result = api.get_job_result(job_id)

cancel_job — cancel a running job

api.cancel_job(job_id)

Full async polling example

# Submit async
result = api.clean_data(source_ids=["guid1", "guid2"], mode='CycleAutoFixup', allow_async=True)
job_id = result['job_id']

# Option A: wait and get result automatically
cleaned_ids = api.wait_for_job(job_id, poll_interval=5, timeout=600)

# Option B: manual polling loop
import time
while True:
    status = api.get_job_status(job_id)
    print(f"  {status['status']} — {status['progress']}%")
    if status['status'] in ('Completed', 'Failed', 'Cancelled'):
        break
    time.sleep(5)

if status['status'] == 'Completed':
    cleaned_ids = api.get_job_result(job_id)

Data Changelog

Retrieve a list of all data sets that have changed since a given timestamp. Useful for syncing or auditing data updates.

Parameters

  • since: str (required) ISO 8601 timestamp. Only items modified after this time are returned. Example: '2025-01-01T00:00:00Z'
  • return_type: str (optional) 'df' (default) returns a flat DataFrame. 'dict' returns the raw response
  • timeout: int (optional) Request timeout in seconds. Default is 120. Increase for wide date ranges

📘 Examples

# Get all changes since a date as a DataFrame
changelog = api.get_changelog(since="2025-01-01T00:00:00Z")
print(f"Changed files: {len(changelog)}")
changelog.head()
# Get raw dict response
changelog = api.get_changelog(since="2025-06-01T00:00:00Z", return_type='dict')
print(changelog['items'])
# Wide date range — increase timeout
changelog = api.get_changelog(since="2024-01-01T00:00:00Z", timeout=300)

Duplicate Files

Retrieve groups of files with similar names that may be duplicates. Each group is a list of file records.

📘 Examples

# Get all duplicate file groups
dupes = api.get_duplicate_files()
print(f"Duplicate groups found: {len(dupes)}")

# Inspect the first group
for item in dupes[0]:
    print(f"  {item['name']} — {item['id']}")
# Archive all but the first file in each duplicate group
for group in dupes:
    for item in group[1:]:  # Keep the first, archive the rest
        api.archive_data(item['id'])

Upload Python Execution Artifact

Attach an output file (PNG, CSV, XLSX, etc.) to a running or completed Python script execution. Called from within a Python script running in the Micantis environment.

Parameters

  • execution_id: str (optional inside cloud executions) The execution ID (GUID) of the running or completed execution. Defaults to the WORKBOOK_EXECUTION_ID environment variable, which cloud executions always set; required when running elsewhere. A non-GUID first positional argument is treated as file_path
  • file_path: str (required) Local path to the file to upload. Maximum size: 50 MB
  • title: str (required) Human-readable title for the artifact
  • filename: str (optional) Override the filename stored on the server. If not provided, derived from the title and file extension
  • mime: str (optional) Content type stored for the artifact (e.g. image/png). If not provided, guessed from the file extension, falling back to application/octet-stream

Returns

  • Dictionary with 'name', 'title', 'contentType', and 'sizeBytes'

📘 Examples

# Inside a cloud execution — execution_id is resolved from the environment
result = api.upload_execution_artifact("voltage_plot.png", title="Voltage vs Time")
print(f"Uploaded: {result['name']} ({result['sizeBytes']:,} bytes)")
# Explicit execution ID with a custom filename and content type
result = api.upload_execution_artifact(
    execution_id="your-execution-guid",
    file_path="results.csv",
    title="Cycle Summary Results",
    filename="cycle_summary_2025.csv",
    mime="text/csv"
)

Metadata

Release files for micantis 1.2.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for micantis 1.2.9
File Size Uploaded
micantis-1.2.9.tar.gz 75.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for micantis 1.2.9
File Interpreter ABI Platform
micantis-1.2.9-py3-none-any.whl Python 3 none any Details

Total release size: 121.7 kB

Release files / micantis-1.2.9.tar.gz

Download URL micantis-1.2.9.tar.gz
Size 75.7 kB
Tags Source
SHA-256 checksum
How to use checksums
9f4f833b2b2522a6ec7d60007cd67aad0177a915fec80a8164d7377ddbfdd111
BLAKE2b-256 checksum
How to use checksums
b33f1a5d24b7472c0a75e9ed9c8a0b84097377ecb22bf5f4c8ee453d6a949193
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.21

Release files / micantis-1.2.9-py3-none-any.whl

Download URL micantis-1.2.9-py3-none-any.whl
Size 46.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
da36cff8f9d539b7ab718e592131758c3884a2e8951d1b321accb3425e619cfc
BLAKE2b-256 checksum
How to use checksums
1bdc6c4cb03c87458e9b9cd35cc47afa290e27e3b0ac9282d15cce799f0c7ea0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.21

Release history Release notifications | RSS feed

This release

1.2.9 This release

2 release files

1.2.8

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.1.19

2 release files

0.1.18

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.15

2 release files

0.1.13

2 release files

0.1.12

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.9

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page