Maccor Reader

class ionworks.data.read.maccor.Maccor[source]

Bases: BaseReader

name: str = 'Maccor'
default_options: dict[str, Any] = {'cell_metadata': {}, 'file_encoding': 'ISO-8859-1', 'skip_capacity_columns': False, 'time_offset_fix': -1, 'timezone': 'UTC'}
run(filename: str | Path, extra_column_mappings: dict[str, str] | None = None, options: dict[str, str] | None = None) → DataFrame[source]

Read and process data from a Maccor file.

Headers are canonicalized before lookup, so a mapping covers that column’s bracket, separator and unit-alias variants; only case is significant. See _canonical_header() for the folding and _get_column_renamings() for the mappings.

“Cycle from cycler” and “Time [s]” are resolved from the data, not the header alone — see _resolve_cycle_column() and _process_test_time_column(). Extra mappings can be supplied via extra_column_mappings.

Parameters:
  • filename (str | Path) – Path to the Maccor file to be read. Supports: - .txt files (tab-separated) - .csv files (comma-separated with units row) - .xls/.xlsx files (Excel format) - Files with .+3digits extension (e.g., .123, .456)

  • extra_column_mappings (dict of str to str, optional) – Dictionary of additional column mappings to use when reading the Maccor file. The keys are the original column names and the values are the new column names. Default is None.

  • options (dict of str to str, optional) –

    Dictionary of options to use when reading the Maccor file. Options are:

    • file_encoding: str, optional

      Encoding format for the Maccor file. Default is “ISO-8859-1”. Note: encoding is not used for Excel files.

    • timezone: str, optional

      Timezone to use for the Maccor file. Default is “UTC”.

    • time_offset_fix: float, optional

      Minimum time difference to enforce between consecutive points. If -1 (default), raises ValueError when time decreases or duplicates. If >= 0, ensures all time differences are at least this value using vectorized operations: fixed_diff = max(diff(time), time_offset_fix), then reconstructs time via cumsum.

    • skip_capacity_columns: bool, optional

      If True, skip reading capacity and energy columns from the raw file. This forces ionworks.data to compute capacity/energy from current/power integration instead. Useful when raw capacity data has resets or other issues. Default is False.

Returns:

Processed data from the Maccor file with standardized column names and units.

Return type:

pl.DataFrame

static set_frame(data: DataFrame) → DataFrame[source]

Add the procedure activation each sample belongs to, from its mode.

Called by run(), and usable on a time series read before the reader wrote the column, provided it kept Mode from cycler.

Parameters:

data (pl.DataFrame) – A Maccor time series, in sample order.

Returns:

The same frame with a Frame column. Returned unchanged when it has no Mode from cycler: the calls cannot be recovered, and no column says so more plainly than one that is absent.

Return type:

pl.DataFrame

static has_time_column(text: str) → bool[source]

Return True if text names a Maccor time column, case-insensitively.

Parameters:

text (str) – A header string, or a whole header line for the CSV/text path, where detection scans a metadata preamble for the real header.

Returns:

True when any known Maccor time-column spelling appears.

Return type:

bool

classmethod sniff_excel(filename: str | Path) → bool[source]

Return True if filename is a Maccor .xls/.xlsx export.

The data sheet is resolved first: a Maccor workbook need not put the time series on the first sheet, and detection must not be narrower than what the reader can read.

Parameters:

filename (str | Path) – Path to the workbook to inspect.

Returns:

True when the resolved sheet carries a step column alongside a Maccor time column, or enough Maccor-shaped columns to be unambiguous.

Return type:

bool

read_header(filename: str | Path, options: dict[str, str] | None = None) → str[source]

Read the header from a Maccor file.

read_start_time(filename: str | Path, extra_column_mappings: dict[str, str] | None = None, options: dict[str, str] | None = None) → datetime | None[source]

Read the start time from a Maccor file.

Parameters:
  • filename (str | Path) – Path to the Maccor file to be read. Supports: - .txt files (tab-separated) - .csv files (comma-separated with units row) - .xls/.xlsx files (Excel format) - Files with .+3digits extension (e.g., .123, .456)

  • options (dict of str to str, optional) – See ionworks.data.read.Maccor.run().

Returns:

The start time of the Maccor file, or None if not found.

Return type:

datetime | None

read_metadata(filename: str | Path, options: dict[str, str] | None = None) → dict[str, Any][source]

Read the descriptive metadata from a Maccor file header.

The Procedure: name identifies the test schedule that produced the file, which is what links a measurement to its protocol on upload.

Parameters:
  • filename (str | Path) – Path to the Maccor file to be read. Supports the same formats as read_start_time().

  • options (dict of str to str, optional) – See ionworks.data.read.Maccor.run().

Returns:

Header fields already grouped the way the measurement API defines them, so the result can be merged into a measurement dict as-is:

  • protocol["name"]: name of the Maccor test schedule.

  • test_setup["export_date"]: Today's Date, when the file was exported.

  • test_setup["source_file_path"]: path it was exported from.

  • test_setup["source_file_id"]: id from a bracketed Comment/Barcode. This belongs to the cycler’s own id space and is not a cross-system identifier – it does not correspond to a recipe, cell or sample id in any other system.

  • test_setup["barcode_comment"]: free-text part of Comment/Barcode.

  • test_setup["channel_number"]: the per-row dialect’s Channel, else the numeric filename extension, which is how Maccor names an export after the channel that produced it (...057 is channel 57).

  • start_time: timezone-aware, from Date of Test or, in the per-row dialect, Started. Top-level, because the API models it as a column rather than inside a group. Same value read_start_time() returns for the flat dialect, so a caller wanting both reads the header once.

Keys the header does not contain are omitted, so an export with no Comment/Barcode yields no barcode keys rather than empty ones.

The dialects carry different fields, so an absent key may mean the dialect does not write it rather than that the value is missing. export_date and source_file_path come from the flat header only. channel_number comes from the per-row header or, for either dialect, a numeric filename extension – so it is absent only for a .txt/.csv/.xlsx name.

Return type:

dict[str, Any]

Embedded procedure

ionworks.data.read.maccor_procedure(source: str | Path | bytes | bytearray | memoryview) → MaccorProcedure[source]

Extract the procedure embedded in a Maccor raw data file.

Parameters:

source (str, Path, bytes, bytearray or memoryview) – Path to a Maccor raw (binary) data file, or its contents. Text exports do not carry the procedure.

Returns:

The master procedure’s name and XML, and each sub-procedure it calls with its XML, or None for those the file does not contain yet.

Return type:

MaccorProcedure

Raises:

ValueError – If the file does not contain an embedded Maccor procedure, or one it contains is not valid XML.

Examples

>>> procedure = iw.data.read.maccor_procedure("TEST.001")
>>> procedure.missing
['Discharge Rate']
class ionworks.data.read.MaccorProcedure(name: str | None, master: str, sub_procedures: dict[str, str | None])[source]

Bases: object

A test procedure recovered from a Maccor raw data file.

sub_procedures has one entry for every sub-procedure the procedure calls, keyed by the name exactly as the calling step writes it, which is the key ionworks_ucp.parse_protocol expects in additional_content. The value is the sub-procedure’s XML, or None when the file does not contain it yet.

name: str | None

The master procedure’s filename without .000, or None when the file header does not name it.

master: str

The master procedure’s XML.

sub_procedures: dict[str, str | None]

Every sub-procedure called, master’s call order first, mapped to its XML or to None when it has not been written to the file yet.

property missing: list[str]

Names of the sub-procedures the file does not contain yet.

property is_complete: bool

Whether the file contains every sub-procedure the procedure calls.