Skip to content

Data Templates

albert.collections.data_templates.DataTemplateCollection

DataTemplateCollection(*, session: AlbertSession)

Bases: BaseCollection

Manage Data Templates in the Albert platform.

A Data Template (DAT, IDs formatted DAT...) defines what a test captures. It has two parts:

  • data_column_values: the measured RESULTS of the test (its data columns, also called "direct variables"). See DataColumnValue and DataColumn.
  • parameter_values: the CONDITIONS under which the test is run (also called "indirect variables"). See ParameterValue and the Parameter collection.

A Data Template does not itself store measured values; those live as Property Data. When a Data Template is paired with a Workflow inside a Block, only its parameters (not its result columns) flow into the Workflow's setpoints.

This collection is accessed as client.data_templates.

Example

from albert import Albert
client = Albert()
dt = client.data_templates.get_by_id(id="DAT9999999")
print(dt.name)
# 'Tensile Strength Test'

Parameters:

Name Type Description Default
session AlbertSession

The authenticated Albert session used for API calls.

required

Attributes:

Name Type Description
base_path str

The base API route for data template requests.

Methods:

Name Description
create

Create a new data template, including its data columns and parameters.

get_by_id

Get a single fully populated template by its ID.

get_by_ids

Get many templates by their IDs in batches.

get_by_name

Get a single template by exact (case-insensitive) name, or None.

search

Fast, lightweight search returning partial items (best for lookups/counts).

get_all

Same filters as search, but returns fully populated templates (slower).

add_data_columns

Attach result data columns to an existing template.

add_parameters

Attach condition parameters to an existing template.

update

Update an existing template.

delete

Delete a template by its ID.

set_curve_example

Set the example row for a curve data column (shown on the details page).

set_image_example

Set the example row for an image data column (shown on the details page).

Parameters:

Name Type Description Default
session AlbertSession

The authenticated Albert session used for API calls.

required
Source code in src/albert/collections/data_templates.py
def __init__(self, *, session: AlbertSession):
    """Initialize a DataTemplateCollection.

    Parameters
    ----------
    session : AlbertSession
        The authenticated Albert session used for API calls.
    """
    super().__init__(session=session)
    self.base_path = f"/api/{DataTemplateCollection._api_version}/datatemplates"

base_path

base_path = f"/api/{DataTemplateCollection._api_version}/datatemplates"

create

create(*, data_template: DataTemplate) -> DataTemplate

Create a new data template.

Creates the template along with its result data columns (data_column_values) and condition parameters (parameter_values). Parameters are attached in a follow-up request after the template itself is created.

Example

from albert.resources.data_templates import DataTemplate, DataColumnValue
template = DataTemplate(
    name="Tensile Strength Test",
    data_column_values=[DataColumnValue(data_column_id="DAC9999999")],
)
created = client.data_templates.create(data_template=template)
created.id
# 'DAT9999999'

Parameters:

Name Type Description Default
data_template DataTemplate

The template to create. name is required. Populate data_column_values with the results the test captures and parameter_values with the conditions under which it is run.

required

Returns:

Type Description
DataTemplate

The newly created template, populated with its assigned Data Template ID.

Source code in src/albert/collections/data_templates.py
def create(self, *, data_template: DataTemplate) -> DataTemplate:
    """Create a new data template.

    Creates the template along with its result data columns
    (``data_column_values``) and condition parameters (``parameter_values``).
    Parameters are attached in a follow-up request after the template itself is
    created.

    !!! example
        ```python
        from albert.resources.data_templates import DataTemplate, DataColumnValue
        template = DataTemplate(
            name="Tensile Strength Test",
            data_column_values=[DataColumnValue(data_column_id="DAC9999999")],
        )
        created = client.data_templates.create(data_template=template)
        created.id
        # 'DAT9999999'
        ```

    Parameters
    ----------
    data_template : DataTemplate
        The template to create. ``name`` is required. Populate
        ``data_column_values`` with the results the test captures and
        ``parameter_values`` with the conditions under which it is run.

    Returns
    -------
    DataTemplate
        The newly created template, populated with its assigned Data Template ID.
    """
    if (
        isinstance(data_template.data_column_values, list)
        and len(data_template.data_column_values) == 0
    ):
        data_template.data_column_values = None
    if data_template.data_column_values is not None:
        for column_value in data_template.data_column_values:
            ensure_data_column_validation(column_value)
    # remove them on the initial post
    parameter_values = data_template.parameter_values
    data_template.parameter_values = None
    response = self.session.post(
        self.base_path,
        json=data_template.model_dump(mode="json", by_alias=True, exclude_none=True),
    )
    dt = DataTemplate(**response.json())
    dt.parameter_values = parameter_values
    if parameter_values is None or len(parameter_values) == 0:
        return dt
    else:
        return self.add_parameters(data_template_id=dt.id, parameters=parameter_values)

get_by_id

get_by_id(*, id: DataTemplateId) -> DataTemplate

Get a single, fully populated data template by its ID.

For retrieving many templates at once, use get_by_ids. To find templates without knowing their IDs, use search or get_all.

Example

dt = client.data_templates.get_by_id(id="DAT9999999")
dt.name
# 'Tensile Strength Test'

Parameters:

Name Type Description Default
id DataTemplateId

The Data Template ID (format DAT..., e.g. "DAT9999999").

required

Returns:

Type Description
DataTemplate

The fully populated template.

Source code in src/albert/collections/data_templates.py
@validate_call
def get_by_id(self, *, id: DataTemplateId) -> DataTemplate:
    """Get a single, fully populated data template by its ID.

    For retrieving many templates at once, use [`get_by_ids`][albert.collections.data_templates.DataTemplateCollection.get_by_ids]. To find
    templates without knowing their IDs, use [`search`][albert.collections.data_templates.DataTemplateCollection.search] or [`get_all`][albert.collections.data_templates.DataTemplateCollection.get_all].

    !!! example
        ```python
        dt = client.data_templates.get_by_id(id="DAT9999999")
        dt.name
        # 'Tensile Strength Test'
        ```

    Parameters
    ----------
    id : DataTemplateId
        The Data Template ID (format ``DAT...``, e.g. ``"DAT9999999"``).

    Returns
    -------
    DataTemplate
        The fully populated template.
    """
    response = self.session.get(f"{self.base_path}/{id}")
    return DataTemplate(**response.json())

get_by_ids

get_by_ids(
    *, ids: list[DataTemplateId]
) -> list[DataTemplate]

Get multiple fully populated data templates by their IDs.

Requests are automatically split into batches, so arbitrarily long ID lists are supported.

Example

templates = client.data_templates.get_by_ids(ids=["DAT9999999", "DAT9999998"])
[t.name for t in templates]
# ['Tensile Strength Test', 'Melt Flow Index']

Parameters:

Name Type Description Default
ids list[DataTemplateId]

The Data Template IDs to retrieve (format DAT...).

required

Returns:

Type Description
list[DataTemplate]

The matching templates.

Source code in src/albert/collections/data_templates.py
@validate_call
def get_by_ids(self, *, ids: list[DataTemplateId]) -> list[DataTemplate]:
    """Get multiple fully populated data templates by their IDs.

    Requests are automatically split into batches, so arbitrarily long ID lists
    are supported.

    !!! example
        ```python
        templates = client.data_templates.get_by_ids(ids=["DAT9999999", "DAT9999998"])
        [t.name for t in templates]
        # ['Tensile Strength Test', 'Melt Flow Index']
        ```

    Parameters
    ----------
    ids : list[DataTemplateId]
        The Data Template IDs to retrieve (format ``DAT...``).

    Returns
    -------
    list[DataTemplate]
        The matching templates.
    """
    url = f"{self.base_path}/ids"
    batches = [ids[i : i + 250] for i in range(0, len(ids), 250)]
    return [
        DataTemplate(**item)
        for batch in batches
        for item in self.session.get(url, params={"id": batch}).json()["Items"]
    ]

get_by_name

get_by_name(*, name: str) -> DataTemplate | None

Get a single, fully populated data template by its exact name.

The match is case-insensitive. If multiple templates share the name, the first match is returned. Returns None when no template matches.

Example

dt = client.data_templates.get_by_name(name="Tensile Strength Test")
dt.id if dt else "no match"
# 'DAT9999999'

Parameters:

Name Type Description Default
name str

The exact name of the data template to retrieve.

required

Returns:

Type Description
DataTemplate or None

The matching template, or None if not found.

Source code in src/albert/collections/data_templates.py
def get_by_name(self, *, name: str) -> DataTemplate | None:
    """Get a single, fully populated data template by its exact name.

    The match is case-insensitive. If multiple templates share the name, the
    first match is returned. Returns None when no template matches.

    !!! example
        ```python
        dt = client.data_templates.get_by_name(name="Tensile Strength Test")
        dt.id if dt else "no match"
        # 'DAT9999999'
        ```

    Parameters
    ----------
    name : str
        The exact name of the data template to retrieve.

    Returns
    -------
    DataTemplate or None
        The matching template, or None if not found.
    """
    for t in self.search(name=name):
        if t.name.lower() == name.lower():
            return t.hydrate()
    return None

add_data_columns

add_data_columns(
    *,
    data_template_id: DataTemplateId,
    data_columns: list[DataColumnValue],
) -> DataTemplate

Add result data columns to an existing data template.

Data columns are the measured results the test captures (its "direct variables"). Any enum validations declared on the columns are created as part of this call.

Example

from albert.resources.data_templates import DataColumnValue
updated = client.data_templates.add_data_columns(
    data_template_id="DAT9999999",
    data_columns=[DataColumnValue(data_column_id="DAC9999999")],
)

Parameters:

Name Type Description Default
data_template_id DataTemplateId

The Data Template ID to add the columns to (format DAT...).

required
data_columns list[DataColumnValue]

The result columns to add. See DataColumnValue.

required

Returns:

Type Description
DataTemplate

The updated template, re-fetched with the new columns.

Source code in src/albert/collections/data_templates.py
@validate_call
def add_data_columns(
    self, *, data_template_id: DataTemplateId, data_columns: list[DataColumnValue]
) -> DataTemplate:
    """Add result data columns to an existing data template.

    Data columns are the measured results the test captures (its "direct
    variables"). Any enum validations declared on the columns are created as part
    of this call.

    !!! example
        ```python
        from albert.resources.data_templates import DataColumnValue
        updated = client.data_templates.add_data_columns(
            data_template_id="DAT9999999",
            data_columns=[DataColumnValue(data_column_id="DAC9999999")],
        )
        ```

    Parameters
    ----------
    data_template_id : DataTemplateId
        The Data Template ID to add the columns to (format ``DAT...``).
    data_columns : list[DataColumnValue]
        The result columns to add. See
        [`DataColumnValue`][albert.resources.data_templates.DataColumnValue].

    Returns
    -------
    DataTemplate
        The updated template, re-fetched with the new columns.
    """
    data_template_url = f"{self.base_path}/{data_template_id}"
    create_data_columns_with_enums(
        session=self.session,
        data_columns_base_url=f"{data_template_url}/datacolumns",
        data_template_url=data_template_url,
        data_columns=data_columns,
    )
    return self.get_by_id(id=data_template_id)

add_parameters

add_parameters(
    *,
    data_template_id: DataTemplateId,
    parameters: list[ParameterValue],
) -> DataTemplate

Add condition parameters to an existing data template.

Parameters are the conditions under which the test is run (its "indirect variables"), and are what flow into a Workflow's setpoints when the template is used in a Block. Any enum validations declared on the parameters are created as part of this call.

Example

from albert.resources.parameter_groups import ParameterValue
updated = client.data_templates.add_parameters(
    data_template_id="DAT9999999",
    parameters=[ParameterValue(id="PRM9999999", value="25")],
)

Parameters:

Name Type Description Default
data_template_id DataTemplateId

The Data Template ID to add the parameters to (format DAT...).

required
parameters list[ParameterValue]

The parameters to add. See ParameterValue.

required

Returns:

Type Description
DataTemplate

The updated template, re-fetched with the new parameters.

Source code in src/albert/collections/data_templates.py
@validate_call
def add_parameters(
    self, *, data_template_id: DataTemplateId, parameters: list[ParameterValue]
) -> DataTemplate:
    """Add condition parameters to an existing data template.

    Parameters are the conditions under which the test is run (its "indirect
    variables"), and are what flow into a Workflow's setpoints when the template is
    used in a Block. Any enum validations declared on the parameters are created as
    part of this call.

    !!! example
        ```python
        from albert.resources.parameter_groups import ParameterValue
        updated = client.data_templates.add_parameters(
            data_template_id="DAT9999999",
            parameters=[ParameterValue(id="PRM9999999", value="25")],
        )
        ```

    Parameters
    ----------
    data_template_id : DataTemplateId
        The Data Template ID to add the parameters to (format ``DAT...``).
    parameters : list[ParameterValue]
        The parameters to add. See
        [`ParameterValue`][albert.resources.parameter_groups.ParameterValue].

    Returns
    -------
    DataTemplate
        The updated template, re-fetched with the new parameters.
    """
    if parameters is None or len(parameters) == 0:
        return self.get_by_id(id=data_template_id)

    parameters_url = f"{self.base_path}/{data_template_id}/parameters"
    create_parameters_with_enums(
        session=self.session,
        parameters_base_url=parameters_url,
        patch_url=parameters_url,
        parameters=parameters,
    )
    return self.get_by_id(id=data_template_id)

search

search(
    *,
    name: str | None = None,
    user_id: UserId | None = None,
    owner: str | list[str] | None = None,
    tags: str | list[str] | None = None,
    data_columns: str | list[str] | None = None,
    standard_organization: str | list[str] | None = None,
    additional_field: str | list[str] | None = None,
    created_by: str | list[str] | None = None,
    from_created_at: str | None = None,
    to_created_at: str | None = None,
    updated_by: str | list[str] | None = None,
    from_updated_at: str | None = None,
    to_updated_at: str | None = None,
    metadata_filters: dict[str, Any] | None = None,
    is_drop_down: bool | None = None,
    sort_by: str | None = None,
    facet_text: str | None = None,
    facet_field: str | None = None,
    contains_field: str | list[str] | None = None,
    contains_text: str | list[str] | None = None,
    search_field: list[str] | None = None,
    search_query_string: str | None = None,
    custom_fields: dict[str, Any] | None = None,
    source_field: list[str] | None = None,
    order_by: OrderBy = DESCENDING,
    max_items: int | None = None,
    offset: int | None = 0,
) -> Iterator[DataTemplateSearchItem]

Search for data templates matching the given filters.

This is the fast path: it returns partial (unhydrated) DataTemplateSearchItem entities and is best for lookups, counts, and pulling IDs. To retrieve fully populated templates, use get_all instead. Results are returned lazily as an iterator that pages through the API on demand.

Example

for item in client.data_templates.search(name="Tensile", max_items=10):
    print(item.id, item.name)

Parameters:

Name Type Description Default
name str

Filter by data template name (text match).

None
user_id UserId

Filter by the ID of an associated user.

None
owner str or list[str]

Filter by owner name(s).

None
tags str or list[str]

Filter by tag name(s).

None
data_columns str or list[str]

Filter by data column name(s).

None
standard_organization str or list[str]

Filter by standards organization name(s).

None
additional_field str or list[str]

Additional fields to include on each returned item. If omitted, a default set of fields is requested.

None
created_by str or list[str]

Filter by creator. Accepts user display name(s) or UserId(s) (e.g. "USR4227" or "Jane Doe").

None
from_created_at str

Only include templates created on or after this date (ISO 8601).

None
to_created_at str

Only include templates created on or before this date (ISO 8601).

None
updated_by str or list[str]

Filter by user(s) who last updated the template. Accepts UserId(s) only (e.g. "USR4227"), not display names.

None
from_updated_at str

Only include templates updated on or after this date (ISO 8601).

None
to_updated_at str

Only include templates updated on or before this date (ISO 8601).

None
metadata_filters dict[str, Any]

Filter by custom field (metadata) values.

None
is_drop_down bool

When True, apply smart dropdown search behavior.

None
sort_by str

Attribute to sort results by.

None
facet_text str

Text to match within a facet search.

None
facet_field str

Field to search within for facet filtering.

None
contains_field str or list[str]

Field(s) to apply a "contains" search to.

None
contains_text str or list[str]

Text value(s) for the "contains" search.

None
search_field list[str]

Restrict which fields the name query searches.

None
search_query_string str

Filter by custom field query string.

None
custom_fields dict[str, Any]

Filter by custom field values.

None
source_field list[str]

Restrict which fields are returned in search results.

None
order_by OrderBy

The order in which to sort results. Default is DESCENDING.

DESCENDING
max_items int

Maximum number of items to return in total. If None, iterates over all matching items.

None

Returns:

Type Description
Iterator[DataTemplateSearchItem]

A lazy iterator of matching partial templates. Call hydrate() on an item to fetch its full DataTemplate.

Source code in src/albert/collections/data_templates.py
@validate_call
def search(
    self,
    *,
    name: str | None = None,
    user_id: UserId | None = None,
    owner: str | list[str] | None = None,
    tags: str | list[str] | None = None,
    data_columns: str | list[str] | None = None,
    standard_organization: str | list[str] | None = None,
    additional_field: str | list[str] | None = None,
    created_by: str | list[str] | None = None,
    from_created_at: str | None = None,
    to_created_at: str | None = None,
    updated_by: str | list[str] | None = None,
    from_updated_at: str | None = None,
    to_updated_at: str | None = None,
    metadata_filters: dict[str, Any] | None = None,
    is_drop_down: bool | None = None,
    sort_by: str | None = None,
    facet_text: str | None = None,
    facet_field: str | None = None,
    contains_field: str | list[str] | None = None,
    contains_text: str | list[str] | None = None,
    search_field: list[str] | None = None,
    search_query_string: str | None = None,
    custom_fields: dict[str, Any] | None = None,
    source_field: list[str] | None = None,
    order_by: OrderBy = OrderBy.DESCENDING,
    max_items: int | None = None,
    offset: int | None = 0,
) -> Iterator[DataTemplateSearchItem]:
    """Search for data templates matching the given filters.

    This is the fast path: it returns partial (unhydrated)
    [`DataTemplateSearchItem`][albert.resources.data_templates.DataTemplateSearchItem] entities and is
    best for lookups, counts, and pulling IDs. To retrieve fully populated
    templates, use [`get_all`][albert.collections.data_templates.DataTemplateCollection.get_all] instead. Results are returned lazily as an
    iterator that pages through the API on demand.

    !!! example
        ```python
        for item in client.data_templates.search(name="Tensile", max_items=10):
            print(item.id, item.name)
        ```

    Parameters
    ----------
    name : str, optional
        Filter by data template name (text match).
    user_id : UserId, optional
        Filter by the ID of an associated user.
    owner : str or list[str], optional
        Filter by owner name(s).
    tags : str or list[str], optional
        Filter by tag name(s).
    data_columns : str or list[str], optional
        Filter by data column name(s).
    standard_organization : str or list[str], optional
        Filter by standards organization name(s).
    additional_field : str or list[str], optional
        Additional fields to include on each returned item. If omitted, a default
        set of fields is requested.
    created_by : str or list[str], optional
        Filter by creator. Accepts user display name(s) or UserId(s) (e.g.
        ``"USR4227"`` or ``"Jane Doe"``).
    from_created_at : str, optional
        Only include templates created on or after this date (ISO 8601).
    to_created_at : str, optional
        Only include templates created on or before this date (ISO 8601).
    updated_by : str or list[str], optional
        Filter by user(s) who last updated the template. Accepts UserId(s)
        only (e.g. ``"USR4227"``), not display names.
    from_updated_at : str, optional
        Only include templates updated on or after this date (ISO 8601).
    to_updated_at : str, optional
        Only include templates updated on or before this date (ISO 8601).
    metadata_filters : dict[str, Any], optional
        Filter by custom field (metadata) values.
    is_drop_down : bool, optional
        When True, apply smart dropdown search behavior.
    sort_by : str, optional
        Attribute to sort results by.
    facet_text : str, optional
        Text to match within a facet search.
    facet_field : str, optional
        Field to search within for facet filtering.
    contains_field : str or list[str], optional
        Field(s) to apply a "contains" search to.
    contains_text : str or list[str], optional
        Text value(s) for the "contains" search.
    search_field : list[str], optional
        Restrict which fields the name query searches.
    search_query_string : str, optional
        Filter by custom field query string.
    custom_fields : dict[str, Any], optional
        Filter by custom field values.
    source_field : list[str], optional
        Restrict which fields are returned in search results.
    order_by : OrderBy, optional
        The order in which to sort results. Default is ``DESCENDING``.
    max_items : int, optional
        Maximum number of items to return in total. If None, iterates over all
        matching items.

    Returns
    -------
    Iterator[DataTemplateSearchItem]
        A lazy iterator of matching partial templates. Call
        `hydrate()` on an
        item to fetch its full [`DataTemplate`][albert.resources.data_templates.DataTemplate].
    """
    payload = {
        "offset": offset,
        "order": order_by,
        "text": name,
        "userId": user_id,
        "isDropDown": is_drop_down,
        "sortBy": sort_by,
        "owner": ensure_list(owner),
        "tags": ensure_list(tags),
        "dataColumns": ensure_list(data_columns),
        "standardOrganization": ensure_list(standard_organization),
        "facetText": facet_text,
        "facetField": facet_field,
        "containsField": ensure_list(contains_field),
        "containsText": ensure_list(contains_text),
        "searchField": ensure_list(search_field),
        "searchQueryString": search_query_string,
        "sourceField": ensure_list(source_field),
        "createdBy": ensure_list(created_by),
        "fromCreatedAt": from_created_at,
        "toCreatedAt": to_created_at,
        "updatedBy": ensure_list(updated_by),
        "fromUpdatedAt": from_updated_at,
        "toUpdatedAt": to_updated_at,
        "additionalField": (
            ensure_list(additional_field)
            if additional_field is not None
            else list(DEFAULT_ADDITIONAL_FIELDS)
        ),
    }
    if metadata_filters is not None:
        payload["metadataFilters"] = {"metadata": metadata_filters}
    if custom_fields is not None:
        payload["customFields"] = {"metadata": custom_fields}

    return AlbertPaginator(
        mode=PaginationMode.OFFSET,
        path=f"{self.base_path}/search",
        session=self.session,
        method="POST",
        json=payload,
        max_items=max_items,
        deserialize=lambda items: [
            DataTemplateSearchItem.model_validate(x)._bind_collection(self) for x in items
        ],
    )

update

update(*, data_template: DataTemplate) -> DataTemplate

Update an existing data template.

Only the fields listed in Notes are applied. New data columns and parameters present on the supplied template (including their enum validations) are created as part of this call.

Example

dt = client.data_templates.get_by_id(id="DAT9999999")
dt.description = "Updated per ASTM D638"
updated = client.data_templates.update(data_template=dt)

Parameters:

Name Type Description Default
data_template DataTemplate

The template to update. Its id must be set and match the template to update. Retrieve it with get_by_id, modify the fields listed in Notes, then pass it here.

required

Returns:

Type Description
DataTemplate

The updated template.

Notes

The following fields can be updated: name, description, and metadata on the template itself, and per-parameter value, unit, required, and validation.

Warnings

Only scalar data column values (text, number, dropdown) can be updated with this method. Use set_curve_example or set_image_example to set example values for curve and image data column types.

Source code in src/albert/collections/data_templates.py
def update(self, *, data_template: DataTemplate) -> DataTemplate:
    """Update an existing data template.

    Only the fields listed in Notes are applied. New data columns and parameters
    present on the supplied template (including their enum validations) are
    created as part of this call.

    !!! example
        ```python
        dt = client.data_templates.get_by_id(id="DAT9999999")
        dt.description = "Updated per ASTM D638"
        updated = client.data_templates.update(data_template=dt)
        ```

    Parameters
    ----------
    data_template : DataTemplate
        The template to update. Its ``id`` must be set and match the template to
        update. Retrieve it with [`get_by_id`][albert.collections.data_templates.DataTemplateCollection.get_by_id], modify the fields listed in
        Notes, then pass it here.

    Returns
    -------
    DataTemplate
        The updated template.

    Notes
    -----
    The following fields can be updated: ``name``, ``description``, and
    ``metadata`` on the template itself, and per-parameter ``value``, ``unit``,
    ``required``, and ``validation``.

    Warnings
    --------
    Only scalar data column values (text, number, dropdown) can be updated with
    this method. Use [`set_curve_example`][albert.collections.data_templates.DataTemplateCollection.set_curve_example] or [`set_image_example`][albert.collections.data_templates.DataTemplateCollection.set_image_example] to set
    example values for curve and image data column types.
    """

    existing = self.get_by_id(id=data_template.id)

    base_payload = self._generate_patch_payload(existing=existing, updated=data_template)

    path = f"{self.base_path}/{existing.id}"
    (
        general_patches,
        new_data_columns,
        data_column_enum_patches,
        new_parameters,
        parameter_enum_patches,
        parameter_patches,
        acl_add_values,
        acl_delete_values,
    ) = generate_data_template_patches(
        initial_patches=base_payload,
        updated_data_template=data_template,
        existing_data_template=existing,
    )

    if len(new_data_columns) > 0:
        create_data_columns_with_enums(
            session=self.session,
            data_columns_base_url=f"{path}/datacolumns",
            data_template_url=path,
            data_columns=new_data_columns,
        )
    existing_columns_by_sequence = {
        x.sequence: x for x in (existing.data_column_values or []) if x.sequence is not None
    }
    if len(data_column_enum_patches) > 0:
        for sequence, enum_patches in data_column_enum_patches.items():
            if len(enum_patches) == 0:
                continue
            existing_column = existing_columns_by_sequence.get(sequence)
            has_existing_enum_validation = (
                existing_column is not None
                and existing_column.validation is not None
                and len(existing_column.validation) > 0
                and existing_column.validation[0].datatype == DataType.ENUM
            )
            if not has_existing_enum_validation:
                continue
            self.session.put(
                f"{self.base_path}/{existing.id}/datacolumns/{sequence}/enums",
                json=enum_patches,  # these are simple dicts for now
            )
    if len(new_parameters) > 0:
        parameters_url = f"{path}/parameters"
        create_parameters_with_enums(
            session=self.session,
            parameters_base_url=parameters_url,
            patch_url=parameters_url,
            parameters=new_parameters,
        )
    enum_sequences = {}
    if len(parameter_enum_patches) > 0:
        for sequence, enum_patches in parameter_enum_patches.items():
            if len(enum_patches) == 0:
                continue

            enums = self.session.put(
                f"{self.base_path}/{existing.id}/parameters/{sequence}/enums",
                json=enum_patches,  # these are simple dicts for now
            )
            enum_sequences[sequence] = [EnumValidationValue(**x) for x in enums.json()]

    # Create validation patches ONLY for sequences that actually have enum changes
    enum_validation_patches = []
    for sequence, enums in enum_sequences.items():
        # Only create validation patch if there were actual enum changes
        if len(enums) > 0:
            enum_validation = ValueValidation(
                datatype=DataType.ENUM,
                value=enums,
            )
            enum_patch = PGPatchDatum(
                rowId=sequence,
                operation="update",
                attribute="validation",
                new_value=[enum_validation],
            )
            enum_validation_patches.append(enum_patch)

    # Combine all parameter patches to avoid duplicates
    all_parameter_patches = []

    if len(parameter_patches) > 0:
        patches_by_sequence = {}
        for p in parameter_patches:
            if p.rowId not in patches_by_sequence:
                patches_by_sequence[p.rowId] = []
            patches_by_sequence[p.rowId].append(p)

        for sequence, patches in patches_by_sequence.items():
            # Filter out validation patches for sequences that have enum sequences
            # because enum validation patches will handle validation for those sequences
            if sequence in enum_sequences:
                patches = [p for p in patches if p.attribute != "validation"]

            all_parameter_patches.extend(patches)

            # Add enum validation patches (these replace any filtered validation patches)
    # Don't add enum validation patches to all_parameter_patches - apply them separately

    # Apply all parameter patches in one request to avoid duplicates
    if len(all_parameter_patches) > 0:
        # Apply enum validation patches one by one to avoid duplicate validation errors
        for patch in enum_validation_patches:
            single_payload = PGPatchPayload(data=[patch])
            single_json = single_payload.model_dump(
                mode="json", by_alias=True, exclude_none=True
            )
            self.session.patch(path + "/parameters", json=single_json)

        # Apply non-enum patches if any
        non_enum_patches = [
            p for p in all_parameter_patches if p not in enum_validation_patches
        ]
        if len(non_enum_patches) > 0:
            payload = PGPatchPayload(data=non_enum_patches)
            json_payload = payload.model_dump(mode="json", by_alias=True, exclude_none=True)
            self.session.patch(
                path + "/parameters",
                json=json_payload,
            )

    acl_add_payload = build_acl_patch_payload(operation="add", values=acl_add_values)
    if acl_add_payload is not None:
        self.session.patch(
            path,
            json=acl_add_payload.model_dump(mode="json", by_alias=True, exclude_none=True),
        )

    acl_delete_payload = build_acl_patch_payload(operation="delete", values=acl_delete_values)
    if acl_delete_payload is not None:
        self.session.patch(
            path,
            json=acl_delete_payload.model_dump(mode="json", by_alias=True, exclude_none=True),
        )

    if len(general_patches.data) > 0:
        payload = GeneralPatchPayload(data=general_patches.data)
        self.session.patch(
            path,
            json=payload.model_dump(mode="json", by_alias=True, exclude_none=True),
        )
    return self.get_by_id(id=data_template.id)

delete

delete(*, id: DataTemplateId) -> None

Delete a data template by its ID.

Example

client.data_templates.delete(id="DAT9999999")

Parameters:

Name Type Description Default
id DataTemplateId

The Data Template ID to delete (format DAT...).

required

Returns:

Type Description
None
Source code in src/albert/collections/data_templates.py
@validate_call
def delete(self, *, id: DataTemplateId) -> None:
    """Delete a data template by its ID.

    !!! example
        ```python
        client.data_templates.delete(id="DAT9999999")
        ```

    Parameters
    ----------
    id : DataTemplateId
        The Data Template ID to delete (format ``DAT...``).

    Returns
    -------
    None
    """
    self.session.delete(f"{self.base_path}/{id}")

get_all

get_all(
    *,
    name: str | None = None,
    user_id: UserId | None = None,
    owner: str | list[str] | None = None,
    tags: str | list[str] | None = None,
    data_columns: str | list[str] | None = None,
    standard_organization: str | list[str] | None = None,
    additional_field: str | list[str] | None = None,
    created_by: str | list[str] | None = None,
    from_created_at: str | None = None,
    to_created_at: str | None = None,
    updated_by: str | list[str] | None = None,
    from_updated_at: str | None = None,
    to_updated_at: str | None = None,
    metadata_filters: dict[str, Any] | None = None,
    is_drop_down: bool | None = None,
    sort_by: str | None = None,
    facet_text: str | None = None,
    facet_field: str | None = None,
    contains_field: str | list[str] | None = None,
    contains_text: str | list[str] | None = None,
    search_field: list[str] | None = None,
    search_query_string: str | None = None,
    custom_fields: dict[str, Any] | None = None,
    source_field: list[str] | None = None,
    order_by: OrderBy = DESCENDING,
    max_items: int | None = None,
    offset: int | None = 0,
) -> Iterator[DataTemplate]

Get fully populated data templates matching the given filters.

This mirrors search but hydrates each match into a complete DataTemplate (via get_by_ids), so it is slower. Use search when you only need lightweight, partial entities. Results are returned lazily as an iterator that pages through the API on demand.

Example

for dt in client.data_templates.get_all(name="Tensile", max_items=10):
    print(dt.id, dt.name)

Parameters:

Name Type Description Default
name str

Filter by data template name (text match).

None
user_id UserId

Filter by the ID of an associated user.

None
owner str or list[str]

Filter by owner name(s).

None
tags str or list[str]

Filter by tag name(s).

None
data_columns str or list[str]

Filter by data column name(s).

None
standard_organization str or list[str]

Filter by standards organization name(s).

None
additional_field str or list[str]

Additional fields to include on each returned item. If omitted, a default set of fields is requested.

None
created_by str or list[str]

Filter by creator. Accepts user display name(s) or UserId(s) (e.g. "USR4227" or "Jane Doe").

None
from_created_at str

Only include templates created on or after this date (ISO 8601).

None
to_created_at str

Only include templates created on or before this date (ISO 8601).

None
updated_by str or list[str]

Filter by user(s) who last updated the template. Accepts UserId(s) only (e.g. "USR4227"), not display names.

None
from_updated_at str

Only include templates updated on or after this date (ISO 8601).

None
to_updated_at str

Only include templates updated on or before this date (ISO 8601).

None
metadata_filters dict[str, Any]

Filter by custom field (metadata) values.

None
is_drop_down bool

When True, apply smart dropdown search behavior.

None
sort_by str

Attribute to sort results by.

None
facet_text str

Text to match within a facet search.

None
facet_field str

Field to search within for facet filtering.

None
contains_field str or list[str]

Field(s) to apply a "contains" search to.

None
contains_text str or list[str]

Text value(s) for the "contains" search.

None
search_field list[str]

Restrict which fields the name query searches.

None
search_query_string str

Filter by custom field query string.

None
custom_fields dict[str, Any]

Filter by custom field values.

None
source_field list[str]

Restrict which fields are returned in search results.

None
order_by OrderBy

The order in which to sort results. Default is DESCENDING.

DESCENDING
max_items int

Maximum number of items to return in total. If None, iterates over all matching items.

None

Returns:

Type Description
Iterator[DataTemplate]

A lazy iterator over fully populated templates. Preserves has_more / total from the underlying search paginator.

Source code in src/albert/collections/data_templates.py
@validate_call
def get_all(
    self,
    *,
    name: str | None = None,
    user_id: UserId | None = None,
    owner: str | list[str] | None = None,
    tags: str | list[str] | None = None,
    data_columns: str | list[str] | None = None,
    standard_organization: str | list[str] | None = None,
    additional_field: str | list[str] | None = None,
    created_by: str | list[str] | None = None,
    from_created_at: str | None = None,
    to_created_at: str | None = None,
    updated_by: str | list[str] | None = None,
    from_updated_at: str | None = None,
    to_updated_at: str | None = None,
    metadata_filters: dict[str, Any] | None = None,
    is_drop_down: bool | None = None,
    sort_by: str | None = None,
    facet_text: str | None = None,
    facet_field: str | None = None,
    contains_field: str | list[str] | None = None,
    contains_text: str | list[str] | None = None,
    search_field: list[str] | None = None,
    search_query_string: str | None = None,
    custom_fields: dict[str, Any] | None = None,
    source_field: list[str] | None = None,
    order_by: OrderBy = OrderBy.DESCENDING,
    max_items: int | None = None,
    offset: int | None = 0,
) -> Iterator[DataTemplate]:
    """Get fully populated data templates matching the given filters.

    This mirrors [`search`][albert.collections.data_templates.DataTemplateCollection.search] but hydrates each match into a complete
    [`DataTemplate`][albert.resources.data_templates.DataTemplate] (via [`get_by_ids`][albert.collections.data_templates.DataTemplateCollection.get_by_ids]), so it is slower. Use
    [`search`][albert.collections.data_templates.DataTemplateCollection.search] when you only need lightweight, partial entities. Results are
    returned lazily as an iterator that pages through the API on demand.

    !!! example
        ```python
        for dt in client.data_templates.get_all(name="Tensile", max_items=10):
            print(dt.id, dt.name)
        ```

    Parameters
    ----------
    name : str, optional
        Filter by data template name (text match).
    user_id : UserId, optional
        Filter by the ID of an associated user.
    owner : str or list[str], optional
        Filter by owner name(s).
    tags : str or list[str], optional
        Filter by tag name(s).
    data_columns : str or list[str], optional
        Filter by data column name(s).
    standard_organization : str or list[str], optional
        Filter by standards organization name(s).
    additional_field : str or list[str], optional
        Additional fields to include on each returned item. If omitted, a default
        set of fields is requested.
    created_by : str or list[str], optional
        Filter by creator. Accepts user display name(s) or UserId(s) (e.g.
        ``"USR4227"`` or ``"Jane Doe"``).
    from_created_at : str, optional
        Only include templates created on or after this date (ISO 8601).
    to_created_at : str, optional
        Only include templates created on or before this date (ISO 8601).
    updated_by : str or list[str], optional
        Filter by user(s) who last updated the template. Accepts UserId(s)
        only (e.g. ``"USR4227"``), not display names.
    from_updated_at : str, optional
        Only include templates updated on or after this date (ISO 8601).
    to_updated_at : str, optional
        Only include templates updated on or before this date (ISO 8601).
    metadata_filters : dict[str, Any], optional
        Filter by custom field (metadata) values.
    is_drop_down : bool, optional
        When True, apply smart dropdown search behavior.
    sort_by : str, optional
        Attribute to sort results by.
    facet_text : str, optional
        Text to match within a facet search.
    facet_field : str, optional
        Field to search within for facet filtering.
    contains_field : str or list[str], optional
        Field(s) to apply a "contains" search to.
    contains_text : str or list[str], optional
        Text value(s) for the "contains" search.
    search_field : list[str], optional
        Restrict which fields the name query searches.
    search_query_string : str, optional
        Filter by custom field query string.
    custom_fields : dict[str, Any], optional
        Filter by custom field values.
    source_field : list[str], optional
        Restrict which fields are returned in search results.
    order_by : OrderBy, optional
        The order in which to sort results. Default is ``DESCENDING``.
    max_items : int, optional
        Maximum number of items to return in total. If None, iterates over all
        matching items.

    Returns
    -------
    Iterator[DataTemplate]
        A lazy iterator over fully populated templates. Preserves ``has_more`` /
        ``total`` from the underlying search paginator.
    """
    source = self.search(
        name=name,
        user_id=user_id,
        owner=owner,
        tags=tags,
        data_columns=data_columns,
        standard_organization=standard_organization,
        additional_field=additional_field,
        created_by=created_by,
        from_created_at=from_created_at,
        to_created_at=to_created_at,
        updated_by=updated_by,
        from_updated_at=from_updated_at,
        to_updated_at=to_updated_at,
        metadata_filters=metadata_filters,
        is_drop_down=is_drop_down,
        sort_by=sort_by,
        facet_text=facet_text,
        facet_field=facet_field,
        contains_field=contains_field,
        contains_text=contains_text,
        search_field=search_field,
        search_query_string=search_query_string,
        custom_fields=custom_fields,
        source_field=source_field,
        order_by=order_by,
        max_items=max_items,
        offset=offset,
    )

    def _hydrated() -> Iterator[DataTemplate]:
        it = (item.id for item in source)
        while batch := list(islice(it, 100)):
            try:
                yield from self.get_by_ids(ids=batch)
            except AlbertHTTPError as e:
                logger.warning(f"Error hydrating batch {batch}: {e}")

    return MetadataPreservingIterator(source, _hydrated())

set_curve_example

set_curve_example(
    *,
    data_template_id: DataTemplateId,
    data_column_id: DataColumnId | None = None,
    data_column_name: str | None = None,
    example: CurveExample,
) -> DataTemplate

Set the example row for a curve data column.

An example row is a sample value displayed only on the Data Template details page (it is not shown in tasks and is not measured Property Data). Curve columns get a dedicated helper because a curve is a complex type sourced from a CSV file or an existing attachment. Identify the target column by exactly one of data_column_id or data_column_name.

Example

from albert.resources.data_templates import CurveExample
updated = client.data_templates.set_curve_example(
    data_template_id="DAT9999999",
    data_column_name="Viscosity Curve",
    example=CurveExample(file_path="curve.csv"),
)

Parameters:

Name Type Description Default
data_template_id DataTemplateId

The Data Template ID that owns the column (format DAT...).

required
data_column_id DataColumnId

The target curve column's ID. Provide exactly one of data_column_id or data_column_name.

None
data_column_name str

The target curve column's name. Provide exactly one of data_column_id or data_column_name.

None
example CurveExample

The curve example to apply. See CurveExample.

required

Returns:

Type Description
DataTemplate

The updated template, re-fetched after the example is applied.

Source code in src/albert/collections/data_templates.py
@validate_call
def set_curve_example(
    self,
    *,
    data_template_id: DataTemplateId,
    data_column_id: DataColumnId | None = None,
    data_column_name: str | None = None,
    example: CurveExample,
) -> DataTemplate:
    """Set the example row for a curve data column.

    An example row is a sample value displayed only on the Data Template details
    page (it is not shown in tasks and is not measured Property Data). Curve
    columns get a dedicated helper because a curve is a complex type sourced from a
    CSV file or an existing attachment. Identify the target column by exactly one
    of ``data_column_id`` or ``data_column_name``.

    !!! example
        ```python
        from albert.resources.data_templates import CurveExample
        updated = client.data_templates.set_curve_example(
            data_template_id="DAT9999999",
            data_column_name="Viscosity Curve",
            example=CurveExample(file_path="curve.csv"),
        )
        ```

    Parameters
    ----------
    data_template_id : DataTemplateId
        The Data Template ID that owns the column (format ``DAT...``).
    data_column_id : DataColumnId, optional
        The target curve column's ID. Provide exactly one of ``data_column_id`` or
        ``data_column_name``.
    data_column_name : str, optional
        The target curve column's name. Provide exactly one of ``data_column_id``
        or ``data_column_name``.
    example : CurveExample
        The curve example to apply. See
        [`CurveExample`][albert.resources.data_templates.CurveExample].

    Returns
    -------
    DataTemplate
        The updated template, re-fetched after the example is applied.
    """
    data_template = self.get_by_id(id=data_template_id)
    target_column = get_target_data_column(
        data_template=data_template,
        data_template_id=data_template_id,
        data_column_id=data_column_id,
        data_column_name=data_column_name,
    )
    payload = build_curve_example(
        session=self.session,
        data_template_id=data_template_id,
        example=example,
        target_column=target_column,
    )
    if not payload.data:
        return data_template
    self.session.patch(
        f"{self.base_path}/{data_template_id}",
        json=payload.model_dump(mode="json", by_alias=True, exclude_none=True),
    )
    return self.get_by_id(id=data_template_id)

set_image_example

set_image_example(
    *,
    data_template_id: DataTemplateId,
    data_column_id: DataColumnId | None = None,
    data_column_name: str | None = None,
    example: ImageExample,
) -> DataTemplate

Set the example row for an image data column.

An example row is a sample value displayed only on the Data Template details page (it is not shown in tasks and is not measured Property Data). Image columns get a dedicated helper because an image is a complex type sourced from a local file. Identify the target column by exactly one of data_column_id or data_column_name.

Example

from albert.resources.data_templates import ImageExample
updated = client.data_templates.set_image_example(
    data_template_id="DAT9999999",
    data_column_name="Fracture Surface",
    example=ImageExample(file_path="fracture.png"),
)

Parameters:

Name Type Description Default
data_template_id DataTemplateId

The Data Template ID that owns the column (format DAT...).

required
data_column_id DataColumnId

The target image column's ID. Provide exactly one of data_column_id or data_column_name.

None
data_column_name str

The target image column's name. Provide exactly one of data_column_id or data_column_name.

None
example ImageExample

The image example to apply. See ImageExample.

required

Returns:

Type Description
DataTemplate

The updated template, re-fetched after the example is applied.

Source code in src/albert/collections/data_templates.py
@validate_call
def set_image_example(
    self,
    *,
    data_template_id: DataTemplateId,
    data_column_id: DataColumnId | None = None,
    data_column_name: str | None = None,
    example: ImageExample,
) -> DataTemplate:
    """Set the example row for an image data column.

    An example row is a sample value displayed only on the Data Template details
    page (it is not shown in tasks and is not measured Property Data). Image
    columns get a dedicated helper because an image is a complex type sourced from
    a local file. Identify the target column by exactly one of ``data_column_id``
    or ``data_column_name``.

    !!! example
        ```python
        from albert.resources.data_templates import ImageExample
        updated = client.data_templates.set_image_example(
            data_template_id="DAT9999999",
            data_column_name="Fracture Surface",
            example=ImageExample(file_path="fracture.png"),
        )
        ```

    Parameters
    ----------
    data_template_id : DataTemplateId
        The Data Template ID that owns the column (format ``DAT...``).
    data_column_id : DataColumnId, optional
        The target image column's ID. Provide exactly one of ``data_column_id`` or
        ``data_column_name``.
    data_column_name : str, optional
        The target image column's name. Provide exactly one of ``data_column_id``
        or ``data_column_name``.
    example : ImageExample
        The image example to apply. See
        [`ImageExample`][albert.resources.data_templates.ImageExample].

    Returns
    -------
    DataTemplate
        The updated template, re-fetched after the example is applied.
    """
    data_template = self.get_by_id(id=data_template_id)
    target_column = get_target_data_column(
        data_template=data_template,
        data_template_id=data_template_id,
        data_column_id=data_column_id,
        data_column_name=data_column_name,
    )
    payload = build_image_example(
        session=self.session,
        data_template_id=data_template_id,
        example=example,
        target_column=target_column,
    )
    if not payload.data:
        return data_template
    self.session.patch(
        f"{self.base_path}/{data_template_id}",
        json=payload.model_dump(mode="json", by_alias=True, exclude_none=True),
    )
    return self.get_by_id(id=data_template_id)