====== Using Python in EasyMorph ======
EasyMorph provides tight integration with Python by means of the [[transformations:callpython|"Call Python" action]] and the "easymorph" Python module that contains low-level bindings for use in Python scripts and is installed automatically with every EasyMorph installation. The action and the module allow:
* Executing a Python script from an EasyMorph workflow
* Obtaining the workflow [[:parameters|parameters]] in the Python script
* Obtaining the input dataset of the [[transformations:callpython|"Call Python" action]] in the Python script
* Returning a result dataset from the Python script as the action's output
* Setting workflow [[transformations:status|status messages]] from the Python script
* Monitoring workflow cancellation requests in the script
* Generating EasyMorph warnings
===== Developing Python scripts for EasyMorph =====
The "easymorph" Python module can (and should) be used when writing Python scripts outside EasyMorph. The module gracefully handles the absence of a calling EasyMorph workflow, which is convenient for Python development in a standalone IDE. The module provides options for substituting workflow parameters and the input dataset with sample values for development and debugging without EasyMorph.
The "easymorph" module is located in the EasyMorph installation folder. Using the module without EasyMorph requires installing the module with the help of [[https://pythonwheels.com/|Python Wheels]] from the subfolder ''Python\dist'' in the EasyMorph installation folder.
===== Supported Python versions =====
* 3.11
* 3.12
* 3.13
===== Limits =====
The current implementation of Python integration in EasyMorph has the following limits:
^ Description ^ Value ^
| Max text string length |1,073,741,823 characters |
| Max rows in a dataset |536,870,897 rows|
| Max columns in a dataset |100,000 columns|
| Max number value* in a dataset cell |79228162514264337593543950335.0|
| Min number value* in a dataset cell |-79228162514264337593543950335.0|
* Number values in EasyMorph are 128-bit fixed-point decimals with 28-29 significant digits with or without the decimal point between them. A loss of precision is possible when converting numbers with a long fractional part to/from the popular Python float data type (64-bit floating point, 15 to 17 significant digits).
===== Sample Python script =====
from datetime import datetime
import time, math
# Import easymorph module. If the script is started by EasyMorph workflow, import
# would automatically read parameters and the input dataset of the Call Python action.
# Module does not have to be installed in this case, EasyMorph would make it available
# for this script via PYTHONPATH envar.
import easymorph as em
# EasyMorph module can used directly from command line as well, which we would refer as 'standalone' mode
# For standalone usage you would need to either add EasyMorph/Python/modules
# to PYTHONPATH or install WHL:` pip install --force-reinstall --no-index --find-links="Python/modules" easymorph `
# (assuming current working dir is EasyMorph installation location)
if em.standalone:
print("Running in standalone mode; easymorph.input is not available")
else:
print(
f"Running from workflow: {em.input.length=}, {em.input.width=}"
) # print rows & columns counts
# Immutable input dataset is provided via easymorph.input.
# Simple way to define default dataset for standalone (when em.input is None):
src: em.Dataset = (
em.input or em.DatasetBuilder().add_column("count", [1, 2, 3]).to_dataset()
)
def build_dataset():
# Build dataset with mixed types and both dict/positional rows
ds = (
em.DatasetBuilder().add_rows(
[
{
"sensor": "S1",
"reading": 0.5,
"status": "ok",
"timestamp": datetime(2025, 1, 1),
},
{
"sensor": "S2",
"reading": None,
# 'status' column value is missing, will insert None and report warning
# "status": "ok", - uncommenting this will fix the warning
"timestamp": None,
},
["S3", 19.8, "ok", datetime(2025, 1, 3)], # positional row
]
)
# Columns can be inserted via add_column; values are filled starting from the first row,
# rest padded to None. Note that there is a fast path for float arrays.
.add_column("last_reported", [1.0, math.nan, 2.0])
).to_dataset()
# Dataset info
print("Column names:", [c.name for c in ds.columns])
print("Row count:", ds.length)
# Columns can be indexed:
c0 = ds.columns[0] # by index
cs = ds.columns["sensor"] # by name
print("ds.columns[0].name:", c0.name, "ds.columns['sensor'].name:", cs.name)
# First value from column 'status'
print("ds['status'][0]:", ds.columns["status"][0])
# Rows are convertible to 'dict'
print("Last row as dict:", ds.rows[-1].to_dict())
print("Last row [reading] value:", ds.rows[-1]["reading"])
# Read a few values from columns
print("sensor[0:2]:", list(cs[0:2]))
print("reading[all]:", list(ds.columns["reading"]))
# Column view to numbers (non-numbers are converted to NaN). This is the most efficient way to get numeric data.
print("Readings as array:", ds.columns["reading"].to_numbers_array())
# Slice rows
first_two = ds.rows[:2]
print("First two statuses:", [r["status"] for r in first_two])
em.yield_output(ds)
# Simple passthrough demo. Note: this is lossy because numbers on the Python side are floats, not decimals
def passthrough():
# yield_output is used to set output of the calling action and can be called only once
# per script exectution. em.yield_output(None) is allowed to explicitly 'return' empty dataset
em.yield_output(
src # em.input can be None if the calling action is set to not pass it
)
# You can get all workflow parameters by calling em.get_params_as_dict()
def show_params():
params = em.get_params_as_dict() or {"placeholder":True}
print("Workflow parameters:", params)
# return params as dataset
em.yield_output(em.DatasetBuilder().add_row(params))
# Shows how to read/write .dset file
def file_operations():
ds = em.DatasetBuilder().add_column("count", [1, 2, 3]).to_dataset()
# Save a dataset to file and read it back
em.save_dataset(ds, "example.dset")
em.yield_output(
em.read_dataset(
"example.dset"
) # returned dataset is immutable just as em.input
)
# Shows how cancellation can be handled in long running script
def cancellation(timeout=20.0):
start_time = time.time()
print("- waiting for cancellation (timeout", timeout, "s)")
while not em.is_cancellation_requested():
if time.time() - start_time > timeout:
raise SystemError("Example script timed out. Expected cancellation.")
time.sleep(0.2)
# At any point where it is logically appropriate you can check if running workflow
# is requesting cancellation. In standalone mode `is_cancellation_requested` returns False.
# Script is not required to raise an exception on cancellation: this is simply one way to handle it
if em.is_cancellation_requested():
raise RuntimeError("Cancelled")
# It is possible to report warnings back to EasyMorp workflow using em.warn function
# Up to 128 warnings can be reported.
def warnings():
em.warn("First warning")
# Unequal column lengths result in a warning issued by DatasetBuilder
em.yield_output(
em.DatasetBuilder().add_column("id", [1, 2]).add_column("count", [1, 2, 3]).to_dataset()
)
# warnings can be reported even after yield_output
em.warn("Second warning", show_callsite=False) # this warning will not include call-site information
# Note: In version 1.0.0 there is no dedicated from/to_df functions yet.
# With glue code (fairly slow) there is a way to convert to/from DataFrame, if needed.
def pandas_interop():
import pandas as pd
def dataset_to_df(ds: em.Dataset) -> pd.DataFrame:
return pd.DataFrame({col.name: list(col) for col in ds.columns})
def dataset_to_df_numeric(ds: em.Dataset) -> pd.DataFrame:
# All columns as float, non-numeric -> NaN.
# This is much faster option for numeric data
return pd.DataFrame({col.name: col.to_numbers_array() for col in ds.columns})
def df_to_dataset(df: pd.DataFrame) -> em.Dataset:
b = em.DatasetBuilder()
for name, series in df.items(): b.add_column(name, series)
return b.to_dataset()
src_df = pd.DataFrame(
{
"C1": [1.0, float("nan"), 3.5],
"C2": [3, None, "c"]
}
)
ds_from_df = df_to_dataset(src_df)
df_from_ds = dataset_to_df(ds_from_df)
out_ds = df_to_dataset(df_from_ds)
em.yield_output(out_ds)
def run_example(mode="standalone"):
print(f"Running in mode '{mode}'")
modes = {
"build_dataset": build_dataset,
"passthrough": passthrough,
"cancellation": cancellation,
"file_operations": file_operations,
"warnings": warnings,
"show_params": show_params,
"pandas_interop": pandas_interop,
}
try:
modes[mode]()
except KeyError:
raise KeyError(f"Unknown mode '{mode}'. Valid modes: {list(modes)}")
# In the workflow, parameter 'mode' is expected to be set; otherwise use 'when_standalone'
run_example(em.get_param("mode", when_standalone="show_params"))
===== Public interface =====
import collections.abc
import numpy
import numpy.typing
import typing
from typing import Any, overload
input: None
standalone: bool
class Column:
def __init__(self, *args, **kwargs) -> None:
"""Initialize self. See help(type(self)) for accurate signature."""
def to_numbers_array(self) -> numpy.typing.NDArray[numpy.float64]:
"""to_numbers_array(self: easymorph.Column) -> numpy.typing.NDArray[numpy.float64]
Returns a copy of the column as an array of floats. Non-numeric values are NaNs.
"""
def __array__(self) -> numpy.typing.NDArray[numpy.float64]:
"""__array__(self: easymorph.Column) -> numpy.typing.NDArray[numpy.float64]
Returns a copy of the column as an array of floats. Non-numeric values are NaNs.
"""
@overload
def __getitem__(self, arg0: typing.SupportsInt) -> None | str | float | bool:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.Column, arg0: typing.SupportsInt) -> None | str | float | bool
2. __getitem__(self: easymorph.Column, arg0: slice) -> easymorph.ColumnSliceView
"""
@overload
def __getitem__(self, arg0: slice) -> ColumnSliceView:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.Column, arg0: typing.SupportsInt) -> None | str | float | bool
2. __getitem__(self: easymorph.Column, arg0: slice) -> easymorph.ColumnSliceView
"""
def __iter__(self) -> collections.abc.Iterator[None | str | float | bool]:
"""__iter__(self: easymorph.Column) -> collections.abc.Iterator[None | str | float | bool]"""
def __len__(self) -> int:
"""__len__(self: easymorph.Column) -> int"""
@property
def name(self) -> str:
"""(arg0: easymorph.Column) -> str"""
class ColumnSliceView:
def __init__(self, *args, **kwargs) -> None:
"""Initialize self. See help(type(self)) for accurate signature."""
def __getitem__(self, arg0: typing.SupportsInt) -> None | str | float | bool:
"""__getitem__(self: easymorph.ColumnSliceView, arg0: typing.SupportsInt) -> None | str | float | bool"""
def __iter__(self) -> collections.abc.Iterator[None | str | float | bool]:
"""__iter__(self: easymorph.ColumnSliceView) -> collections.abc.Iterator[None | str | float | bool]"""
def __len__(self) -> int:
"""__len__(self: easymorph.ColumnSliceView) -> int"""
class ColumnsRange:
def __init__(self, *args, **kwargs) -> None:
"""Initialize self. See help(type(self)) for accurate signature."""
def __contains__(self, arg0: str) -> bool:
"""__contains__(self: easymorph.ColumnsRange, arg0: str) -> bool"""
@overload
def __getitem__(self, arg0: typing.SupportsInt) -> Column:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.ColumnsRange, arg0: typing.SupportsInt) -> easymorph.Column
2. __getitem__(self: easymorph.ColumnsRange, arg0: str) -> easymorph.Column
"""
@overload
def __getitem__(self, arg0: str) -> Column:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.ColumnsRange, arg0: typing.SupportsInt) -> easymorph.Column
2. __getitem__(self: easymorph.ColumnsRange, arg0: str) -> easymorph.Column
"""
def __iter__(self) -> collections.abc.Iterator[Column]:
"""__iter__(self: easymorph.ColumnsRange) -> collections.abc.Iterator[easymorph.Column]"""
def __len__(self) -> int:
"""__len__(self: easymorph.ColumnsRange) -> int"""
class Dataset:
"""Immutable columnar dataset."""
def __init__(self, *args, **kwargs) -> None:
"""Initialize self. See help(type(self)) for accurate signature."""
@overload
def get_cell(self, column: typing.SupportsInt, row: typing.SupportsInt) -> None | str | float | bool:
"""get_cell(*args, **kwargs)
Overloaded function.
1. get_cell(self: easymorph.Dataset, column: typing.SupportsInt, row: typing.SupportsInt) -> None | str | float | bool
Get cell data as bool | str | float or None.
2. get_cell(self: easymorph.Dataset, column: str, row: typing.SupportsInt) -> None | str | float | bool
Get cell data as bool | str | float or None.
"""
@overload
def get_cell(self, column: str, row: typing.SupportsInt) -> None | str | float | bool:
"""get_cell(*args, **kwargs)
Overloaded function.
1. get_cell(self: easymorph.Dataset, column: typing.SupportsInt, row: typing.SupportsInt) -> None | str | float | bool
Get cell data as bool | str | float or None.
2. get_cell(self: easymorph.Dataset, column: str, row: typing.SupportsInt) -> None | str | float | bool
Get cell data as bool | str | float or None.
"""
def get_cell_as_date(self, column: typing.SupportsInt, row: typing.SupportsInt) -> object:
"""get_cell_as_date(self: easymorph.Dataset, column: typing.SupportsInt, row: typing.SupportsInt) -> object
Try converting numeric cell value to datetime.
"""
@overload
def get_cell_as_text(self, column: typing.SupportsInt, row: typing.SupportsInt) -> str:
"""get_cell_as_text(*args, **kwargs)
Overloaded function.
1. get_cell_as_text(self: easymorph.Dataset, column: typing.SupportsInt, row: typing.SupportsInt) -> str
Get cell content as text string.
2. get_cell_as_text(self: easymorph.Dataset, column: str, row: typing.SupportsInt) -> str
Get cell content as text string.
"""
@overload
def get_cell_as_text(self, column: str, row: typing.SupportsInt) -> str:
"""get_cell_as_text(*args, **kwargs)
Overloaded function.
1. get_cell_as_text(self: easymorph.Dataset, column: typing.SupportsInt, row: typing.SupportsInt) -> str
Get cell content as text string.
2. get_cell_as_text(self: easymorph.Dataset, column: str, row: typing.SupportsInt) -> str
Get cell content as text string.
"""
@property
def columns(self) -> ColumnsRange:
"""Column view.
(arg0: easymorph.Dataset) -> easymorph.ColumnsRange
"""
@property
def length(self) -> int:
"""Number of rows.
(arg0: easymorph.Dataset) -> int
"""
@property
def rows(self) -> RowsView:
"""Row view.
(arg0: easymorph.Dataset) -> easymorph.RowsView
"""
@property
def width(self) -> int:
"""Number of columns.
(arg0: easymorph.Dataset) -> int
"""
class DatasetBuilder:
"""Incrementally builds a columnar Dataset in native memory."""
def __init__(self) -> None:
"""__init__(self: easymorph.DatasetBuilder) -> None"""
@overload
def add_column(self, arg0: str, arg1: collections.abc.Iterable) -> DatasetBuilder:
"""add_column(*args, **kwargs)
Overloaded function.
1. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Iterable) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
2. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Sequence[typing.SupportsFloat]) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
"""
@overload
def add_column(self, name, values) -> Any:
"""add_column(*args, **kwargs)
Overloaded function.
1. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Iterable) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
2. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Sequence[typing.SupportsFloat]) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
"""
@overload
def add_column(self, arg0: str, arg1: collections.abc.Sequence[typing.SupportsFloat]) -> DatasetBuilder:
"""add_column(*args, **kwargs)
Overloaded function.
1. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Iterable) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
2. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Sequence[typing.SupportsFloat]) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
"""
@overload
def add_column(self, name, values) -> Any:
"""add_column(*args, **kwargs)
Overloaded function.
1. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Iterable) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
2. add_column(self: easymorph.DatasetBuilder, arg0: str, arg1: collections.abc.Sequence[typing.SupportsFloat]) -> easymorph.DatasetBuilder
add_column(name, values)
Bulk append rows to specified column. Creates column if it is not found.
Notes
-----
- This is fastest way to build a dataset.
"""
@overload
def add_columns(self, columns: dict) -> DatasetBuilder:
"""add_columns(self: easymorph.DatasetBuilder, columns: dict) -> easymorph.DatasetBuilder
add_columns(columns)
Add several columns in a single call.
Parameters
----------
columns : Mapping[str, Iterable[Any] | numpy.ndarray]
Dict mapping column names to data.
- Fast path: a 1D float64 array.
- Otherwise: any iterable of convertible values.
Returns
-------
DatasetBuilder
The builder itself (chainable).
Raises
------
TypeError | ValueError
When a value cannot be represented as EasyMorph cell type.
"""
@overload
def add_columns(self, columns) -> Any:
"""add_columns(self: easymorph.DatasetBuilder, columns: dict) -> easymorph.DatasetBuilder
add_columns(columns)
Add several columns in a single call.
Parameters
----------
columns : Mapping[str, Iterable[Any] | numpy.ndarray]
Dict mapping column names to data.
- Fast path: a 1D float64 array.
- Otherwise: any iterable of convertible values.
Returns
-------
DatasetBuilder
The builder itself (chainable).
Raises
------
TypeError | ValueError
When a value cannot be represented as EasyMorph cell type.
"""
@overload
def add_row(self, record: object) -> DatasetBuilder:
"""add_row(self: easymorph.DatasetBuilder, record: object) -> easymorph.DatasetBuilder
add_row(record)
Append a single row.
Parameters
----------
record : dict[str, Any] | Sequence[Any]
- Mapping: keys become column names; missing columns are padded
with empty cells. Extra keys create new columns on the fly.
- Sequence: values are written by position; missing tail values
are padded. New columns are created when the sequence is longer
than the current width.
Raises
------
TypeError
If *record* is neither a dict nor a sequence.
"""
@overload
def add_row(self, record) -> Any:
"""add_row(self: easymorph.DatasetBuilder, record: object) -> easymorph.DatasetBuilder
add_row(record)
Append a single row.
Parameters
----------
record : dict[str, Any] | Sequence[Any]
- Mapping: keys become column names; missing columns are padded
with empty cells. Extra keys create new columns on the fly.
- Sequence: values are written by position; missing tail values
are padded. New columns are created when the sequence is longer
than the current width.
Raises
------
TypeError
If *record* is neither a dict nor a sequence.
"""
@overload
def add_rows(self, records: collections.abc.Iterable) -> DatasetBuilder:
"""add_rows(self: easymorph.DatasetBuilder, records: collections.abc.Iterable) -> easymorph.DatasetBuilder
add_rows(records)
Bulk append rows from any iterable that yields row objects.
Parameters
----------
records : Iterable[Any]
Objects accepted by add_row.
Notes
-----
- This is a bit faster than calling `add_row` in a Python loop.
"""
@overload
def add_rows(self, records) -> Any:
"""add_rows(self: easymorph.DatasetBuilder, records: collections.abc.Iterable) -> easymorph.DatasetBuilder
add_rows(records)
Bulk append rows from any iterable that yields row objects.
Parameters
----------
records : Iterable[Any]
Objects accepted by add_row.
Notes
-----
- This is a bit faster than calling `add_row` in a Python loop.
"""
@overload
def to_dataset(self, reset: bool = ...) -> Dataset:
"""to_dataset(self: easymorph.DatasetBuilder, reset: bool = True) -> easymorph.Dataset
to_dataset(reset=True)
Finalize the builder and return an immutable dataset.
Parameters
----------
reset : bool, default True
Clear the builder after the dataset is created.
Returns
-------
Dataset
Resulting immutable dataset.
"""
@overload
def to_dataset(self, reset=...) -> Any:
"""to_dataset(self: easymorph.DatasetBuilder, reset: bool = True) -> easymorph.Dataset
to_dataset(reset=True)
Finalize the builder and return an immutable dataset.
Parameters
----------
reset : bool, default True
Clear the builder after the dataset is created.
Returns
-------
Dataset
Resulting immutable dataset.
"""
@property
def column_names(self) -> list[str]:
"""Return a list of all column names.
(arg0: easymorph.DatasetBuilder) -> list[str]
"""
@property
def length(self) -> int:
"""Number of rows.
(arg0: easymorph.DatasetBuilder) -> int
"""
@property
def width(self) -> int:
"""Number of columns.
(arg0: easymorph.DatasetBuilder) -> int
"""
class ErrorValue:
"""EasyMorph error cell value."""
def __init__(self, arg0: str) -> None:
"""__init__(self: easymorph.ErrorValue, arg0: str) -> None"""
@property
def text(self) -> str:
"""(self: easymorph.ErrorValue) -> str"""
class Row:
def __init__(self, *args, **kwargs) -> None:
"""Initialize self. See help(type(self)) for accurate signature."""
def to_dict(self) -> dict:
"""to_dict(self: easymorph.Row) -> dict"""
@overload
def __getitem__(self, arg0: typing.SupportsInt) -> None | str | float | bool:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.Row, arg0: typing.SupportsInt) -> None | str | float | bool
2. __getitem__(self: easymorph.Row, arg0: str) -> None | str | float | bool
"""
@overload
def __getitem__(self, arg0: str) -> None | str | float | bool:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.Row, arg0: typing.SupportsInt) -> None | str | float | bool
2. __getitem__(self: easymorph.Row, arg0: str) -> None | str | float | bool
"""
def __len__(self) -> int:
"""__len__(self: easymorph.Row) -> int"""
class RowsView:
def __init__(self, *args, **kwargs) -> None:
"""Initialize self. See help(type(self)) for accurate signature."""
@overload
def __getitem__(self, arg0: typing.SupportsInt) -> Row:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.RowsView, arg0: typing.SupportsInt) -> easymorph.Row
2. __getitem__(self: easymorph.RowsView, arg0: slice) -> easymorph.RowsView
"""
@overload
def __getitem__(self, arg0: slice) -> RowsView:
"""__getitem__(*args, **kwargs)
Overloaded function.
1. __getitem__(self: easymorph.RowsView, arg0: typing.SupportsInt) -> easymorph.Row
2. __getitem__(self: easymorph.RowsView, arg0: slice) -> easymorph.RowsView
"""
def __iter__(self) -> collections.abc.Iterator[Row]:
"""__iter__(self: easymorph.RowsView) -> collections.abc.Iterator[easymorph.Row]"""
def __len__(self) -> int:
"""__len__(self: easymorph.RowsView) -> int"""
def get_param(key: str, when_standalone: object = ...) -> object:
"""get_param(key: str, when_standalone: object = None) -> object
Get parameter passed from the calling workflow. Optional argument for standalone scripts.
"""
def get_param_as_date(key: str, when_standalone: object = ...) -> object:
"""get_param_as_date(key: str, when_standalone: object = None) -> object
Return a workflow parameter converted to datetime. Raises if not convertible. Optional argument for standalone scripts.
"""
def get_params_as_dict(errors_as_values: bool = ...) -> dict:
"""get_params_as_dict(errors_as_values: bool = False) -> dict
Return all workflow parameters as a dict.
"""
def is_cancellation_requested() -> bool:
"""is_cancellation_requested() -> bool
Return True if the EasyMorph engine requested cancellation; the script should exit soon.
"""
def number_to_date(arg0: typing.SupportsFloat) -> object:
"""number_to_date(arg0: typing.SupportsFloat) -> object
Convert OADate number to datetime.
"""
def read_dataset(arg0: str) -> Dataset:
"""read_dataset(arg0: str) -> easymorph.Dataset
Read a dataset from disk.
Parameters
----------
fname : str | os.PathLike
Path to an EasyMorph .dset file.
Returns
-------
Dataset
Immutable dataset loaded into native memory.
Raises
------
RuntimeError | ValueError
When the file is not a valid dataset.
"""
def save_dataset(arg0: Dataset, arg1: str) -> None:
"""save_dataset(arg0: easymorph.Dataset, arg1: str) -> None
Save a dataset to disk.
Parameters
----------
output_dset : Dataset
Dataset to write.
fname : str | os.PathLike
Target file path.
Raises
------
ValueError
If *output_dset* is None.
"""
def warn(msg: str, show_callsite: bool = ...) -> None:
"""warn(msg: str, show_callsite: bool = True) -> None
Log a warning message to the EasyMorph engine.
Parameters
----------
msg : str
Warning text.
show_callsite : bool, default True
Include the call-site line when True.
Notes
-----
- The message is recorded only in the module's internal warning collection, it's not
passed to python's `warnings`.
"""
@overload
def yield_output(arg0: Dataset) -> None:
"""yield_output(*args, **kwargs)
Overloaded function.
1. yield_output(arg0: easymorph.Dataset) -> None
Sets the output of calling EasyMorph action. Has no effect in standalone mode.
2. yield_output(arg0: easymorph.DatasetBuilder) -> None
Sets the output of calling EasyMorph action. Has no effect in standalone mode.
"""
@overload
def yield_output(arg0: DatasetBuilder) -> None:
"""yield_output(*args, **kwargs)
Overloaded function.
1. yield_output(arg0: easymorph.Dataset) -> None
Sets the output of calling EasyMorph action. Has no effect in standalone mode.
2. yield_output(arg0: easymorph.DatasetBuilder) -> None
Sets the output of calling EasyMorph action. Has no effect in standalone mode.
"""