Skip to content

Custom Fields

albert.collections.custom_fields

AlbertSession

AlbertSession(
    *,
    base_url: str,
    token: str | None = None,
    client_credentials: ClientCredentials | 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 requests. (e.g., "https://sandbox.albertinvent.com")

required
retries int

The number of retries for failed requests. Defaults to 3.

None
client_credentials ClientCredentials | None

The client credentials for programmatic authentication. Optional if token is provided.

None
token str | None

The JWT token for authentication. Optional if client credentials are provided.

None

Methods:

Name Description
request
Source code in src/albert/session.py
def __init__(
    self,
    *,
    base_url: str,
    token: str | None = None,
    client_credentials: ClientCredentials | 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 client_credentials is None:
        raise ValueError("Either client credentials or token must be specified.")

    self._provided_token = token
    self._token_manager = (
        TokenManager(base_url, client_credentials) if client_credentials is not None else None
    )

    # 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/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

CustomField

Bases: BaseResource

A custom field for an entity in Albert.

Returns:

Type Description
CustomField

A CustomField that can be used to attach Metadata to an entity in Albert.

Attributes:

Name Type Description
name str

The name of the custom field. Cannot contain spaces.

id str | None

The Albert ID of the custom field.

field_type FieldType

The type of the custom field. Allowed values are list and string. String fields cannot be searchable and are used to set uncontrolled metadata. List fields can be searchable and are used to set controlled metadata.

display_name str

The display name of the custom field. Can contain spaces.

searchable bool | None

Whether the custom field is searchable, optional. Defaults to False.

service ServiceType

The service type the custom field is associated with.

hidden bool | None

Whether the custom field is hidden, optional. Defaults to False.

lookup_column bool | None

Whether the custom field is a lookup column, optional. Defaults to False. Only allowed for inventories.

lookup_row bool | None

Whether the custom field is a lookup row, optional. Defaults to False. Only allowed for formulas in inventories.

category FieldCategory | None

The category of the custom field, optional. Defaults to None. Required for list fields. Allowed values are businessDefined and userDefined.

min int | None

The minimum value of the custom field, optional. Defaults to None.

max int | None

The maximum value of the custom field, optional. Defaults to None.

entity_categories list[EntityCategory] | None

The entity categories of the custom field, optional. Defaults to None. Required for lookup row fields. Allowed values are Formulas, RawMaterials, Consumables, Equipment, Property, Batch, and General.

ui_components list[UIComponent] | None

The UI components available to the custom field, optional. Defaults to None. Allowed values are create and details.

Methods:

Name Description
confirm_field_compatability

category class-attribute instance-attribute

category: FieldCategory | None = Field(default=None)

default class-attribute instance-attribute

default: str | None = Field(default=None)

display_name class-attribute instance-attribute

display_name: str = Field(default=None, alias='labelName')

entity_categories class-attribute instance-attribute

entity_categories: list[EntityCategory] | None = Field(
    default=None, alias="entityCategory"
)

field_type class-attribute instance-attribute

field_type: FieldType = Field(alias='type')

hidden class-attribute instance-attribute

hidden: bool | None = Field(default=None)

id class-attribute instance-attribute

id: str | None = Field(default=None, alias='albertId')

lookup_column class-attribute instance-attribute

lookup_column: bool | None = Field(
    default=None, alias="lkpColumn"
)

lookup_row class-attribute instance-attribute

lookup_row: bool | None = Field(
    default=None, alias="lkpRow"
)

max class-attribute instance-attribute

max: int | None = Field(default=None)

min class-attribute instance-attribute

min: int | None = Field(default=None)

multiselect class-attribute instance-attribute

multiselect: bool | None = Field(default=None)

name instance-attribute

name: str

pattern class-attribute instance-attribute

pattern: str | None = Field(default=None)

required class-attribute instance-attribute

required: bool | None = Field(default=None)

searchable class-attribute instance-attribute

searchable: bool | None = Field(
    default=None, alias="search"
)

service instance-attribute

service: ServiceType

ui_components class-attribute instance-attribute

ui_components: list[UIComponent] | None = Field(
    default=None, alias="ui_components"
)

confirm_field_compatability

confirm_field_compatability() -> CustomField
Source code in src/albert/resources/custom_fields.py
@model_validator(mode="after")
def confirm_field_compatability(self) -> "CustomField":
    if self.field_type == FieldType.LIST and self.category is None:
        raise ValueError("Category must be set for list fields")
    return self

CustomFieldCollection

CustomFieldCollection(*, session: AlbertSession)

Bases: BaseCollection

CustomFieldCollection is a collection class for managing CustomField entities in the Albert platform.

This collection provides methods to create, update, retrieve, and list custom fields. CustomFields allow you to store custom metadata on a Project, InventoryItem, User, BaseTask (Tasks), and Lot.

The FieldType used determines the shape of the metadata field's value. If the FieldType is LIST, then the FieldCategory defines the ACL needed to add new allowed items to the given list:

  • FieldCategory.USER_DEFINED: allows general users to add items
  • FieldCategory.BUSINESS_DEFINED: only admins can add new items to the list
Example
# Creating some custom fields
from albert import Albert
from albert.resources.custom_fields import CustomField, FieldCategory, FieldType, ServiceType
from albert.resources.lists import ListItem
from albert.resources.project import Project

# Initialize the Albert client
client = Albert()

# Define the custom fields
stage_gate_field = CustomField(
    name="stage_gate_status",
    display_name="Stage Gate",
    field_type=FieldType.LIST,
    service=ServiceType.PROJECTS,
    min=1,
    max=1,
    category=FieldCategory.BUSINESS_DEFINED  # Defined by the business
)
justification_field = CustomField(
    name="justification",
    display_name="Project Justification",
    field_type=FieldType.STRING,
    service=ServiceType.PROJECTS,
)

# Create the custom fields
client.custom_fields.create(custom_field=stage_gate_field)
client.custom_fields.create(custom_field=justification_field)

Parameters:

Name Type Description Default
session AlbertSession

The Albert session instance.

required

Methods:

Name Description
create

Create a new CustomField item.

get_by_id

Get a CustomField item by its ID.

get_by_name

Get a CustomField item by its name.

list

Searches for CustomField items based on the provided parameters.

update

Update a CustomField item.

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

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

base_path instance-attribute

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

create

create(*, custom_field: CustomField) -> CustomField

Create a new CustomField item.

Parameters:

Name Type Description Default
custom_field CustomField

The CustomField item to create.

required

Returns:

Type Description
CustomField

The created CustomField item with its ID.

Source code in src/albert/collections/custom_fields.py
def create(self, *, custom_field: CustomField) -> CustomField:
    """Create a new CustomField item.

    Parameters
    ----------
    custom_field : CustomField
        The CustomField item to create.

    Returns
    -------
    CustomField
        The created CustomField item with its ID.
    """
    response = self.session.post(
        self.base_path,
        json=custom_field.model_dump(by_alias=True, exclude_none=True, mode="json"),
    )
    return CustomField(**response.json())

get_by_id

get_by_id(*, id: str) -> CustomField

Get a CustomField item by its ID.

Parameters:

Name Type Description Default
id str

The ID of the CustomField item.

required

Returns:

Type Description
CustomField

The CustomField item.

Source code in src/albert/collections/custom_fields.py
def get_by_id(self, *, id: str) -> CustomField:
    """Get a CustomField item by its ID.

    Parameters
    ----------
    id : str
        The ID of the CustomField item.

    Returns
    -------
    CustomField
        The CustomField item.
    """
    response = self.session.get(f"{self.base_path}/{id}")
    return CustomField(**response.json())

get_by_name

get_by_name(
    *, name: str, service: ServiceType | None = None
) -> CustomField | None

Get a CustomField item by its name.

Parameters:

Name Type Description Default
name str

The name of the CustomField item.

required
service ServiceType | None

The service the field relates to, by default None

None

Returns:

Type Description
CustomField | None

The CustomField item, or None if not found.

Source code in src/albert/collections/custom_fields.py
def get_by_name(self, *, name: str, service: ServiceType | None = None) -> CustomField | None:
    """Get a CustomField item by its name.

    Parameters
    ----------
    name : str
        The name of the CustomField item.
    service : ServiceType | None, optional
        The service the field relates to, by default None

    Returns
    -------
    CustomField | None
        The CustomField item, or None if not found.
    """
    for custom_field in self.list(name=name, service=service):
        if custom_field.name.lower() == name.lower():
            return custom_field
    return None

list

list(
    *,
    name: str | None = None,
    service: ServiceType | None = None,
    lookup_column: bool | None = None,
    lookup_row: bool | None = None,
) -> Iterator[CustomField]

Searches for CustomField items based on the provided parameters.

Parameters:

Name Type Description Default
name str | None

The name of the field, by default None

None
service ServiceType | None

The related service the field is in, by default None

None
lookup_column bool | None

Whether the field relates to a lookup column, by default None

None
lookup_row bool | None

Whether the field relates to a lookup row, by default None

None

Yields:

Type Description
Iterator[CustomField]

Returns an iterator of CustomField items matching the search criteria.

Source code in src/albert/collections/custom_fields.py
def list(
    self,
    *,
    name: str | None = None,
    service: ServiceType | None = None,
    lookup_column: bool | None = None,
    lookup_row: bool | None = None,
) -> Iterator[CustomField]:
    """Searches for CustomField items based on the provided parameters.

    Parameters
    ----------
    name : str | None, optional
        The name of the field, by default None
    service : ServiceType | None, optional
        The related service the field is in, by default None
    lookup_column : bool | None, optional
        Whether the field relates to a lookup column, by default None
    lookup_row : bool | None, optional
        Whether the field relates to a lookup row, by default None

    Yields
    ------
    Iterator[CustomField]
        Returns an iterator of CustomField items matching the search criteria.
    """
    params = {
        "name": name,
        "service": service if service else None,
        "lookupColumn": json.dumps(lookup_column) if lookup_column is not None else None,
        "lookupRow": json.dumps(lookup_row) if lookup_row is not None else None,
    }
    return AlbertPaginator(
        mode=PaginationMode.KEY,
        path=self.base_path,
        params=params,
        session=self.session,
        deserialize=lambda items: [CustomField(**item) for item in items],
    )

update

update(*, custom_field: CustomField) -> CustomField

Update a CustomField item.

Parameters:

Name Type Description Default
custom_field CustomField

The updated CustomField item. The ID must be set and match the Field you want to update.

required

Returns:

Type Description
CustomField

The updated CustomField item as registered in Albert.

Source code in src/albert/collections/custom_fields.py
def update(self, *, custom_field: CustomField) -> CustomField:
    """Update a CustomField item.

    Parameters
    ----------
    custom_field : CustomField
        The updated CustomField item. The ID must be set and match the Field you want to update.

    Returns
    -------
    CustomField
        The updated CustomField item as registered in Albert.
    """
    # fetch current object state
    current_object = self.get_by_id(id=custom_field.id)

    # generate the patch payload
    payload = self._generate_patch_payload(
        existing=current_object,
        updated=custom_field,
        generate_metadata_diff=False,
        stringify_values=False,
    )

    for patch in payload.data:
        if (
            patch.attribute in ("hidden", "search", "lkpColumn", "lkpRow")
            and patch.operation == "add"
        ):
            patch.operation = "update"
            patch.old_value = False
        if (
            patch.attribute in ("entityCategory")
            and patch.operation == "add"
            and isinstance(patch.new_value, list)
        ):
            patch.new_value = patch.new_value[0]

    # run patch
    url = f"{self.base_path}/{custom_field.id}"
    self.session.patch(url, json=payload.model_dump(mode="json", by_alias=True))
    updated_ctf = self.get_by_id(id=custom_field.id)
    return updated_ctf

ServiceType

Bases: str, Enum

The service type the custom field is associated with

DATA_COLUMNS class-attribute instance-attribute

DATA_COLUMNS = 'datacolumns'

DATA_TEMPLATES class-attribute instance-attribute

DATA_TEMPLATES = 'datatemplates'

INVENTORIES class-attribute instance-attribute

INVENTORIES = 'inventories'

LOTS class-attribute instance-attribute

LOTS = 'lots'

PARAMETERS class-attribute instance-attribute

PARAMETERS = 'parameters'

PARAMETER_GROUPS class-attribute instance-attribute

PARAMETER_GROUPS = 'parametergroups'

PROJECTS class-attribute instance-attribute

PROJECTS = 'projects'

TASKS class-attribute instance-attribute

TASKS = 'tasks'

USERS class-attribute instance-attribute

USERS = 'users'