Skip to content

Tags

albert.collections.tags.TagCollection

TagCollection(*, session: AlbertSession)

Bases: BaseCollection

Manage Tags in the Albert platform.

A Tag is a freeform text label used to categorize and connect entities across the platform, such as inventory items, companies, and tasks. Tags are shared: the same tag can be applied to many entities, which makes them useful for grouping and filtering related records.

Because tags are identified by their text, the common pattern is to find an existing tag or create it on demand via get_or_create. Tags are referenced by their Tag ID (format TAG..., e.g. "TAG1").

This collection is accessed as client.tags.

Example

from albert import Albert
client = Albert()
tag = client.tags.get_or_create(tag="high-priority")
print(tag.id, tag.tag)

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 tag requests.

Methods:

Name Description
create

Create a new tag.

get_or_create

Return the existing tag matching the name, or create it.

get_by_id

Get a single tag by its ID.

get_by_ids

Get many tags by their IDs.

get_by_name

Get a tag by name, or None if not found.

get_all

Iterate over tags with optional filters.

rename

Rename an existing tag.

delete

Delete a tag by its ID.

exists

Check whether a tag with the given name exists.

Parameters:

Name Type Description Default
session AlbertSession

The authenticated Albert session used for API calls.

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

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

base_path

base_path = f'/api/{TagCollection._api_version}/tags'

exists

exists(*, tag: str, exact_match: bool = True) -> bool

Check whether a tag with the given name exists.

Example

if client.tags.exists(tag="high-priority"):
    print("tag already defined")

Parameters:

Name Type Description Default
tag str

The tag name to check.

required
exact_match bool

Whether to match the name exactly, by default True.

True

Returns:

Type Description
bool

True if a matching tag exists, False otherwise.

Source code in src/albert/collections/tags.py
def exists(self, *, tag: str, exact_match: bool = True) -> bool:
    """Check whether a tag with the given name exists.

    !!! example
        ```python
        if client.tags.exists(tag="high-priority"):
            print("tag already defined")
        ```

    Parameters
    ----------
    tag : str
        The tag name to check.
    exact_match : bool, optional
        Whether to match the name exactly, by default True.

    Returns
    -------
    bool
        True if a matching tag exists, False otherwise.
    """

    return self.get_by_name(name=tag, exact_match=exact_match) is not None

create

create(*, tag: str | Tag) -> Tag

Create a new tag.

Example

tag = client.tags.create(tag="experimental")

Parameters:

Name Type Description Default
tag str or Tag

The tag to create, given either as a plain name or a Tag.

required

Returns:

Type Description
Tag

The newly created tag, including its assigned Tag ID.

Source code in src/albert/collections/tags.py
def create(self, *, tag: str | Tag) -> Tag:
    """Create a new tag.

    !!! example
        ```python
        tag = client.tags.create(tag="experimental")
        ```

    Parameters
    ----------
    tag : str or Tag
        The tag to create, given either as a plain name or a [`Tag`][albert.resources.tags.Tag].

    Returns
    -------
    Tag
        The newly created tag, including its assigned Tag ID.
    """
    if isinstance(tag, str):
        tag = Tag(tag=tag)

    payload = {"name": tag.tag}
    response = self.session.post(self.base_path, json=payload)
    tag = Tag(**response.json())
    return tag

get_or_create

get_or_create(*, tag: str | Tag) -> Tag

Return the existing tag matching the given name, or create it.

Looks for an existing tag with the same name (exact match). If one is found it is returned unchanged; otherwise a new tag is created. This is the recommended way to reference a tag, since tags are shared by name.

Example

tag = client.tags.get_or_create(tag="high-priority")

Parameters:

Name Type Description Default
tag str or Tag

The tag to find or create, given either as a plain name or a Tag.

required

Returns:

Type Description
Tag

The existing or newly created tag.

Source code in src/albert/collections/tags.py
def get_or_create(self, *, tag: str | Tag) -> Tag:
    """Return the existing tag matching the given name, or create it.

    Looks for an existing tag with the same name (exact match). If one is
    found it is returned unchanged; otherwise a new tag is created. This is
    the recommended way to reference a tag, since tags are shared by name.

    !!! example
        ```python
        tag = client.tags.get_or_create(tag="high-priority")
        ```

    Parameters
    ----------
    tag : str or Tag
        The tag to find or create, given either as a plain name or a
        [`Tag`][albert.resources.tags.Tag].

    Returns
    -------
    Tag
        The existing or newly created tag.
    """
    if isinstance(tag, str):
        tag = Tag(tag=tag)
    found = self.get_by_name(name=tag.tag, exact_match=True)
    if found:
        logging.warning(f"Tag {found.tag} already exists with id {found.id}")
        return found
    return self.create(tag=tag)

get_by_id

get_by_id(*, id: TagId) -> Tag

Get a single tag by its ID.

Example

tag = client.tags.get_by_id(id="TAG1")

Parameters:

Name Type Description Default
id TagId

The Tag ID to retrieve (format TAG...).

required

Returns:

Type Description
Tag

The fully populated tag.

Source code in src/albert/collections/tags.py
@validate_call
def get_by_id(self, *, id: TagId) -> Tag:
    """Get a single tag by its ID.

    !!! example
        ```python
        tag = client.tags.get_by_id(id="TAG1")
        ```

    Parameters
    ----------
    id : TagId
        The Tag ID to retrieve (format ``TAG...``).

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

get_by_ids

get_by_ids(*, ids: list[TagId]) -> list[Tag]

Get many tags by their IDs.

IDs are fetched in batches, so arbitrarily long lists are supported.

Example

tags = client.tags.get_by_ids(ids=["TAG1", "TAG2"])

Parameters:

Name Type Description Default
ids list[TagId]

The Tag IDs to retrieve.

required

Returns:

Type Description
list[Tag]

The matching tags. Tags not found are omitted.

Source code in src/albert/collections/tags.py
@validate_call
def get_by_ids(self, *, ids: list[TagId]) -> list[Tag]:
    """Get many tags by their IDs.

    IDs are fetched in batches, so arbitrarily long lists are supported.

    !!! example
        ```python
        tags = client.tags.get_by_ids(ids=["TAG1", "TAG2"])
        ```

    Parameters
    ----------
    ids : list[TagId]
        The Tag IDs to retrieve.

    Returns
    -------
    list[Tag]
        The matching tags. Tags not found are omitted.
    """
    url = f"{self.base_path}/ids"
    batches = [ids[i : i + 100] for i in range(0, len(ids), 100)]
    return [
        Tag(**item)
        for batch in batches
        for item in self.session.get(url, params={"id": batch}).json()
    ]

get_by_name

get_by_name(
    *, name: str, exact_match: bool = True
) -> Tag | None

Get a tag by its name.

Example

tag = client.tags.get_by_name(name="high-priority")

Parameters:

Name Type Description Default
name str

The tag name to retrieve.

required
exact_match bool

Whether to match the name exactly, by default True.

True

Returns:

Type Description
Tag or None

The matching tag, or None if no tag with that name exists.

Source code in src/albert/collections/tags.py
def get_by_name(self, *, name: str, exact_match: bool = True) -> Tag | None:
    """Get a tag by its name.

    !!! example
        ```python
        tag = client.tags.get_by_name(name="high-priority")
        ```

    Parameters
    ----------
    name : str
        The tag name to retrieve.
    exact_match : bool, optional
        Whether to match the name exactly, by default True.

    Returns
    -------
    Tag or None
        The matching tag, or None if no tag with that name exists.
    """
    found = self.get_all(name=name, exact_match=exact_match, max_items=1)
    return next(found, None)

delete

delete(*, id: TagId) -> None

Delete a tag by its ID.

Example

client.tags.delete(id="TAG1")

Parameters:

Name Type Description Default
id TagId

The Tag ID to delete.

required

Returns:

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

    !!! example
        ```python
        client.tags.delete(id="TAG1")
        ```

    Parameters
    ----------
    id : TagId
        The Tag ID to delete.

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

rename

rename(*, old_name: str, new_name: str) -> Tag

Rename an existing tag.

The tag is looked up by its current name and updated in place, so every entity carrying the tag reflects the new name.

Example

tag = client.tags.rename(old_name="high-priority", new_name="urgent")

Parameters:

Name Type Description Default
old_name str

The current name of the tag.

required
new_name str

The new name to give the tag.

required

Returns:

Type Description
Tag

The renamed tag.

Raises:

Type Description
AlbertException

If no tag with old_name is found.

Source code in src/albert/collections/tags.py
def rename(self, *, old_name: str, new_name: str) -> Tag:
    """Rename an existing tag.

    The tag is looked up by its current name and updated in place, so every
    entity carrying the tag reflects the new name.

    !!! example
        ```python
        tag = client.tags.rename(old_name="high-priority", new_name="urgent")
        ```

    Parameters
    ----------
    old_name : str
        The current name of the tag.
    new_name : str
        The new name to give the tag.

    Returns
    -------
    Tag
        The renamed tag.

    Raises
    ------
    AlbertException
        If no tag with ``old_name`` is found.
    """
    found_tag = self.get_by_name(name=old_name, exact_match=True)
    if not found_tag:
        msg = f'Tag "{old_name}" not found.'
        logger.error(msg)
        raise AlbertException(msg)
    tag_id = found_tag.id
    payload = [
        {
            "data": [
                {
                    "operation": "update",
                    "attribute": "name",
                    "oldValue": old_name,
                    "newValue": new_name,
                }
            ],
            "id": tag_id,
        }
    ]
    self.session.patch(self.base_path, json=payload)
    return self.get_by_id(id=tag_id)

get_all

get_all(
    *,
    order_by: OrderBy = DESCENDING,
    name: str | list[str] | None = None,
    exact_match: bool = True,
    start_key: str | None = None,
    max_items: int | None = None,
) -> Iterator[Tag]

Iterate over tags, with optional filters.

Results are fetched page by page as you iterate, so this scales to large result sets without loading everything at once.

Example

for tag in client.tags.get_all(max_items=100):
    print(tag.tag)

Parameters:

Name Type Description Default
order_by OrderBy

Sort direction for results. Defaults to OrderBy.DESCENDING.

DESCENDING
name str or list[str]

Filter tags by one or more names.

None
exact_match bool

Whether to match the name(s) exactly. Defaults to True.

True
start_key str

Pagination key to resume iteration from a previous position.

None
max_items int

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

None

Returns:

Type Description
Iterator[Tag]

An iterator over the matching tags.

Source code in src/albert/collections/tags.py
def get_all(
    self,
    *,
    order_by: OrderBy = OrderBy.DESCENDING,
    name: str | list[str] | None = None,
    exact_match: bool = True,
    start_key: str | None = None,
    max_items: int | None = None,
) -> Iterator[Tag]:
    """Iterate over tags, with optional filters.

    Results are fetched page by page as you iterate, so this scales to large
    result sets without loading everything at once.

    !!! example
        ```python
        for tag in client.tags.get_all(max_items=100):
            print(tag.tag)
        ```

    Parameters
    ----------
    order_by : OrderBy, optional
        Sort direction for results. Defaults to ``OrderBy.DESCENDING``.
    name : str or list[str], optional
        Filter tags by one or more names.
    exact_match : bool, optional
        Whether to match the name(s) exactly. Defaults to True.
    start_key : str, optional
        Pagination key to resume iteration from a previous position.
    max_items : int, optional
        Maximum number of tags to return in total. If None, iterates over all
        matching tags.

    Returns
    -------
    Iterator[Tag]
        An iterator over the matching tags.
    """
    params = {
        "orderBy": order_by,
        "startKey": start_key,
    }

    if name:
        params["name"] = ensure_list(name)
        params["exactMatch"] = exact_match

    return AlbertPaginator(
        mode=PaginationMode.KEY,
        path=self.base_path,
        session=self.session,
        params=params,
        max_items=max_items,
        deserialize=lambda items: [Tag(**item) for item in items],
    )