Skip to content

Custom Templates

albert.collections.custom_templates

logger module-attribute

logger = create_logger()

AlbertHTTPError

AlbertHTTPError(response: Response)

Bases: AlbertException

Base class for all erors due to HTTP responses.

Source code in src/albert/exceptions.py
def __init__(self, response: requests.Response):
    message = self._format_message(response)
    super().__init__(message)
    self.response = response

response instance-attribute

response = response

AlbertPaginator

AlbertPaginator(
    *,
    path: str,
    mode: PaginationMode,
    session: AlbertSession,
    deserialize: Callable[
        [Iterable[dict]], Iterable[ItemType]
    ],
    params: dict[str, str] | None = None,
)

Bases: Iterator[ItemType]

Helper class for pagination through Albert endpoints.

Two pagination modes are possible: - Offset-based via by the offset query parameter - Key-based via by the startKey query parameter and 'lastKey' response field

A custom deserialize function is provided when additional logic is required to load the raw items returned by the search listing, e.g., making additional Albert API calls.

Source code in src/albert/core/pagination.py
def __init__(
    self,
    *,
    path: str,
    mode: PaginationMode,
    session: AlbertSession,
    deserialize: Callable[[Iterable[dict]], Iterable[ItemType]],
    params: dict[str, str] | None = None,
):
    self.path = path
    self.mode = mode
    self.session = session
    self.deserialize = deserialize

    params = params or {}
    self.params = {k: v for k, v in params.items() if v is not None}

    if "startKey" in self.params:
        self.params["startKey"] = quote_plus(self.params["startKey"])

    self._iterator = self._create_iterator()

deserialize instance-attribute

deserialize = deserialize

mode instance-attribute

mode = mode

params instance-attribute

params = {k: _Nfor (k, v) in items() if v is not None}

path instance-attribute

path = path

session instance-attribute

session = session

AlbertSession

AlbertSession(
    *,
    base_url: str,
    token: str | None = None,
    auth_manager: AlbertClientCredentials
    | AlbertSSOClient
    | None = None,
    retries: int | None = None,
)

Bases: Session

A session that has a base URL, which is prefixed to all request URLs.

Parameters:

Name Type Description Default
base_url str

The base URL to prefix to all relative request paths (e.g., "https://app.albertinvent.com").

required
token str | None

A static JWT token for authentication. Ignored if auth_manager is provided.

None
auth_manager AlbertClientCredentials | AlbertSSOClient

An authentication manager used to dynamically fetch and refresh tokens. If provided, it overrides token.

None
retries int

The number of automatic retries on failed requests (default is 3).

None

Methods:

Name Description
request
Source code in src/albert/core/session.py
def __init__(
    self,
    *,
    base_url: str,
    token: str | None = None,
    auth_manager: AlbertClientCredentials | AlbertSSOClient | None = None,
    retries: int | None = None,
):
    super().__init__()
    self.base_url = base_url
    self.headers.update(
        {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "User-Agent": f"albert-SDK V.{albert.__version__}",
        }
    )

    if token is None and auth_manager is None:
        raise ValueError("Either `token` or `auth_manager` must be specified.")

    self._auth_manager = auth_manager
    self._provided_token = token

    # Set up retry logic
    retries = retries if retries is not None else 3
    retry = Retry(
        total=retries,
        read=retries,
        connect=retries,
        backoff_factor=0.3,
        status_forcelist=(500, 502, 503, 504, 403),
        raise_on_status=False,
    )
    adapter = HTTPAdapter(max_retries=retry)
    self.mount("http://", adapter)
    self.mount("https://", adapter)

base_url instance-attribute

base_url = base_url

request

request(
    method: str, path: str, *args, **kwargs
) -> Response
Source code in src/albert/core/session.py
def request(self, method: str, path: str, *args, **kwargs) -> requests.Response:
    self.headers["Authorization"] = f"Bearer {self._access_token}"
    full_url = urljoin(self.base_url, path) if not path.startswith("http") else path
    with handle_http_errors():
        response = super().request(method, full_url, *args, **kwargs)
        response.raise_for_status()
        return response

BaseCollection

BaseCollection(*, session: AlbertSession)

BaseCollection is the base class for all collection classes.

Parameters:

Name Type Description Default
session AlbertSession

The Albert API Session instance.

required
Source code in src/albert/collections/base.py
def __init__(self, *, session: AlbertSession):
    self.session = session

session instance-attribute

session = session

CustomTemplate

Bases: BaseTaggedResource

A custom template entity.

Attributes:

Name Type Description
name str

The name of the template.

id str

The Albert ID of the template. Set when the template is retrieved from Albert.

category TemplateCategory

The category of the template. Allowed values are Property Task, Property, Batch, Sheet, Notebook, and General.

metadata Dict[str, str | List[EntityLink] | EntityLink] | None

The metadata of the template. Allowed Metadata fields can be found using Custim Fields.

data CustomTemplateData | None

The data of the template.

team List[TeamACL] | None

The team of the template.

acl TemplateACL | None

Methods:

Name Description
add_missing_category

Initialize private attributes from the incoming data dictionary before the model is fully constructed.

acl class-attribute instance-attribute

acl: TemplateACL | None = Field(
    default_factory=list, alias="ACL"
)

category class-attribute instance-attribute

category: TemplateCategory = Field(default=GENERAL)

data class-attribute instance-attribute

data: CustomTemplateData | None = Field(
    default=None, alias="Data"
)

id class-attribute instance-attribute

id: str = Field(alias='albertId')

metadata class-attribute instance-attribute

metadata: dict[str, MetadataItem] | None = Field(
    default=None, alias="Metadata"
)

name instance-attribute

name: str

team class-attribute instance-attribute

team: list[TeamACL] | None = Field(default_factory=list)

add_missing_category classmethod

add_missing_category(
    data: dict[str, Any],
) -> dict[str, Any]

Initialize private attributes from the incoming data dictionary before the model is fully constructed.

Source code in src/albert/resources/custom_templates.py
@model_validator(mode="before")  # Must happen before construction so the data are captured
@classmethod
def add_missing_category(cls, data: dict[str, Any]) -> dict[str, Any]:
    """
    Initialize private attributes from the incoming data dictionary before the model is fully constructed.
    """

    if "Data" in data and "category" in data and "category" not in data["Data"]:
        data["Data"]["category"] = data["category"]
    return data

CustomTemplateSearchItem pydantic-model

Bases: BaseAlbertModel, HydrationMixin[CustomTemplate]

Show JSON schema:
{
  "$defs": {
    "ACLType": {
      "enum": [
        "team",
        "member",
        "owner",
        "viewer"
      ],
      "title": "ACLType",
      "type": "string"
    },
    "AccessControlLevel": {
      "description": "The fine grain control",
      "enum": [
        "ProjectOwner",
        "ProjectEditor",
        "ProjectViewer",
        "ProjectAllTask",
        "ProjectPropertyTask",
        "InventoryOwner",
        "InventoryViewer",
        "CustomTemplateOwner",
        "CustomTemplateViewer"
      ],
      "title": "AccessControlLevel",
      "type": "string"
    },
    "CustomTemplateSearchItemACL": {
      "properties": {
        "id": {
          "description": "The id of the user for which this ACL applies",
          "title": "Id",
          "type": "string"
        },
        "fgc": {
          "anyOf": [
            {
              "$ref": "#/$defs/AccessControlLevel"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "The Fine-Grain Control Level"
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Name"
        },
        "userType": {
          "anyOf": [
            {
              "$ref": "#/$defs/UserClass"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "type": {
          "$ref": "#/$defs/ACLType"
        }
      },
      "required": [
        "id",
        "type"
      ],
      "title": "CustomTemplateSearchItemACL",
      "type": "object"
    },
    "CustomTemplateSearchItemData": {
      "properties": {
        "Designs": {
          "default": null,
          "items": {
            "$ref": "#/$defs/DesignLink"
          },
          "title": "Designs",
          "type": "array"
        },
        "FormulaInfo": {
          "items": {},
          "title": "Formulainfo",
          "type": "array"
        },
        "TaskRows": {
          "items": {
            "$ref": "#/$defs/EntityLink"
          },
          "title": "Taskrows",
          "type": "array"
        }
      },
      "title": "CustomTemplateSearchItemData",
      "type": "object"
    },
    "CustomTemplateSearchItemTeam": {
      "properties": {
        "id": {
          "title": "Id",
          "type": "string"
        },
        "name": {
          "title": "Name",
          "type": "string"
        },
        "type": {
          "anyOf": [
            {
              "$ref": "#/$defs/ACLType"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "fgc": {
          "anyOf": [
            {
              "$ref": "#/$defs/AccessControlLevel"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        }
      },
      "required": [
        "id",
        "name"
      ],
      "title": "CustomTemplateSearchItemTeam",
      "type": "object"
    },
    "DesignLink": {
      "properties": {
        "id": {
          "title": "Id",
          "type": "string"
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Name"
        },
        "type": {
          "$ref": "#/$defs/DesignType"
        }
      },
      "required": [
        "id",
        "type"
      ],
      "title": "DesignLink",
      "type": "object"
    },
    "DesignType": {
      "description": "The type of Design",
      "enum": [
        "apps",
        "products",
        "results",
        "process"
      ],
      "title": "DesignType",
      "type": "string"
    },
    "EntityLink": {
      "properties": {
        "id": {
          "title": "Id",
          "type": "string"
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Name"
        }
      },
      "required": [
        "id"
      ],
      "title": "EntityLink",
      "type": "object"
    },
    "SecurityClass": {
      "description": "The security class of a resource",
      "enum": [
        "shared",
        "restricted",
        "confidential",
        "private",
        "public"
      ],
      "title": "SecurityClass",
      "type": "string"
    },
    "Status": {
      "description": "The status of a resource",
      "enum": [
        "active",
        "inactive"
      ],
      "title": "Status",
      "type": "string"
    },
    "UserClass": {
      "description": "The ACL class level of the user",
      "enum": [
        "guest",
        "standard",
        "trusted",
        "privileged",
        "admin"
      ],
      "title": "UserClass",
      "type": "string"
    }
  },
  "properties": {
    "name": {
      "title": "Name",
      "type": "string"
    },
    "albertId": {
      "title": "Albertid",
      "type": "string"
    },
    "createdByName": {
      "title": "Createdbyname",
      "type": "string"
    },
    "createdAt": {
      "title": "Createdat",
      "type": "string"
    },
    "category": {
      "title": "Category",
      "type": "string"
    },
    "status": {
      "anyOf": [
        {
          "$ref": "#/$defs/Status"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "resourceClass": {
      "anyOf": [
        {
          "$ref": "#/$defs/SecurityClass"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "data": {
      "anyOf": [
        {
          "$ref": "#/$defs/CustomTemplateSearchItemData"
        },
        {
          "type": "null"
        }
      ],
      "default": null
    },
    "acl": {
      "items": {
        "$ref": "#/$defs/CustomTemplateSearchItemACL"
      },
      "title": "Acl",
      "type": "array"
    },
    "team": {
      "items": {
        "$ref": "#/$defs/CustomTemplateSearchItemTeam"
      },
      "title": "Team",
      "type": "array"
    }
  },
  "required": [
    "name",
    "albertId",
    "createdByName",
    "createdAt",
    "category",
    "acl",
    "team"
  ],
  "title": "CustomTemplateSearchItem",
  "type": "object"
}

Fields:

acl pydantic-field

acl: list[CustomTemplateSearchItemACL]

category pydantic-field

category: str

created_at pydantic-field

created_at: str

created_by_name pydantic-field

created_by_name: str

data pydantic-field

data: CustomTemplateSearchItemData | None = None

id pydantic-field

id: str

name pydantic-field

name: str

resource_class pydantic-field

resource_class: SecurityClass | None = None

status pydantic-field

status: Status | None = None

team pydantic-field

team: list[CustomTemplateSearchItemTeam]

CustomTemplatesCollection

CustomTemplatesCollection(*, session: AlbertSession)

Bases: BaseCollection

CustomTemplatesCollection is a collection class for managing CustomTemplate entities in the Albert platform.

Parameters:

Name Type Description Default
session AlbertSession

The Albert session instance.

required

Methods:

Name Description
get_all

Retrieve fully hydrated CustomTemplate entities with optional filters.

get_by_id

Get a Custom Template by ID

search

Search for CustomTemplate matching the provided criteria.

Source code in src/albert/collections/custom_templates.py
def __init__(self, *, session: AlbertSession):
    """
    Initializes the CustomTemplatesCollection with the provided session.

    Parameters
    ----------
    session : AlbertSession
        The Albert session instance.
    """
    super().__init__(session=session)
    self.base_path = f"/api/{CustomTemplatesCollection._api_version}/customtemplates"

base_path instance-attribute

base_path = f'/api/{_api_version}/customtemplates'

get_all

get_all(
    *,
    text: str | None = None,
    limit: int = 50,
    offset: int = 0,
) -> Iterator[CustomTemplate]

Retrieve fully hydrated CustomTemplate entities with optional filters.

This method returns complete entity data using get_by_id. Use :meth:search for faster retrieval when you only need lightweight, partial (unhydrated) entities.

Source code in src/albert/collections/custom_templates.py
def get_all(
    self,
    *,
    text: str | None = None,
    limit: int = 50,
    offset: int = 0,
) -> Iterator[CustomTemplate]:
    """Retrieve fully hydrated CustomTemplate entities with optional filters.

    This method returns complete entity data using `get_by_id`.
    Use :meth:`search` for faster retrieval when you only need lightweight, partial (unhydrated) entities.
    """

    for item in self.search(text=text, limit=limit, offset=offset):
        try:
            yield self.get_by_id(id=item.id)
        except AlbertHTTPError as e:
            logger.warning(f"Error hydrating custom template {id}: {e}")

get_by_id

get_by_id(*, id) -> CustomTemplate

Get a Custom Template by ID

Parameters:

Name Type Description Default
id str

id of the custom template

required

Returns:

Type Description
CustomTemplate

The CutomTemplate with the provided ID (or None if not found)

Source code in src/albert/collections/custom_templates.py
def get_by_id(self, *, id) -> CustomTemplate:
    """Get a Custom Template by ID

    Parameters
    ----------
    id : str
        id of the custom template

    Returns
    -------
    CustomTemplate
        The CutomTemplate with the provided ID (or None if not found)
    """
    url = f"{self.base_path}/{id}"
    response = self.session.get(url)
    return CustomTemplate(**response.json())

search

search(
    *,
    text: str | None = None,
    limit: int = 50,
    offset: int = 0,
) -> Iterator[CustomTemplateSearchItem]

Search for CustomTemplate matching the provided criteria.

⚠️ This method returns partial (unhydrated) entities to optimize performance. To retrieve fully detailed entities, use :meth:get_all instead.

Parameters:

Name Type Description Default
text str | None

The text to search for, by default None

None

Yields:

Type Description
Iterator[CustomTemplateSearchItem]

An iterator of CustomTemplateSearchItem items matching the search criteria.

Source code in src/albert/collections/custom_templates.py
def search(
    self,
    *,
    text: str | None = None,
    limit: int = 50,
    offset: int = 0,
) -> Iterator[CustomTemplateSearchItem]:
    """Search for CustomTemplate matching the provided criteria.

    ⚠️ This method returns partial (unhydrated) entities to optimize performance.
    To retrieve fully detailed entities, use :meth:`get_all` instead.

    Parameters
    ----------
    text : str | None, optional
        The text to search for, by default None


    Yields
    ------
    Iterator[CustomTemplateSearchItem]
        An iterator of CustomTemplateSearchItem items matching the search criteria.
    """

    params = {"limit": limit, "offset": offset, "text": text}

    return AlbertPaginator(
        mode=PaginationMode.OFFSET,
        path=f"{self.base_path}/search",
        session=self.session,
        params=params,
        deserialize=lambda items: [
            CustomTemplateSearchItem.model_validate(x)._bind_collection(self) for x in items
        ],
    )

PaginationMode

Bases: str, Enum

KEY class-attribute instance-attribute

KEY = 'key'

OFFSET class-attribute instance-attribute

OFFSET = 'offset'