Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/collections/reference_attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: albert.collections.reference_attributes.ReferenceAttributeCollection
1 change: 1 addition & 0 deletions docs/resources/reference_attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: albert.resources.reference_attributes
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ nav:
- Product Design: collections/product_design.md
- Projects: collections/projects.md
- Property Data: collections/property_data.md
- Reference Attributes: collections/reference_attributes.md
- Reports: collections/reports.md
- Roles: collections/roles.md
- Storage Classes: collections/storage_classes.md
Expand Down Expand Up @@ -204,6 +205,7 @@ nav:
- Product Design: resources/product_design.md
- Projects: resources/projects.md
- Property Data: resources/property_data.md
- Reference Attributes: resources/reference_attributes.md
- Reports: resources/reports.md
- Roles: resources/roles.md
- Storage Classes: resources/storage_classes.md
Expand Down
2 changes: 1 addition & 1 deletion src/albert/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

__all__ = ["Albert", "AlbertClientCredentials", "AlbertSSOClient"]

__version__ = "1.9.6"
__version__ = "2.0.0b1"
5 changes: 5 additions & 0 deletions src/albert/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from albert.collections.product_design import ProductDesignCollection
from albert.collections.projects import ProjectCollection
from albert.collections.property_data import PropertyDataCollection
from albert.collections.reference_attributes import ReferenceAttributeCollection
from albert.collections.report_templates import ReportTemplateCollection
from albert.collections.reports import ReportCollection
from albert.collections.roles import RoleCollection
Expand Down Expand Up @@ -272,6 +273,10 @@ def parameters(self) -> ParameterCollection:
def property_data(self) -> PropertyDataCollection:
return PropertyDataCollection(session=self.session)

@property
def reference_attributes(self) -> ReferenceAttributeCollection:
return ReferenceAttributeCollection(session=self.session)

@property
def product_design(self) -> ProductDesignCollection:
return ProductDesignCollection(session=self.session)
Expand Down
150 changes: 122 additions & 28 deletions src/albert/collections/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
from albert.core.shared.identifiers import (
InventoryId,
ProjectId,
ReferenceAttributeId,
SearchProjectId,
WorksheetId,
)
from albert.resources.facet import FacetItem
from albert.resources.inventory import (
ALL_MERGE_MODULES,
InventoryAttribute,
InventoryAttributeList,
InventoryAttributeUpdate,
InventoryCategory,
InventoryItem,
InventorySearchItem,
InventorySpec,
InventorySpecList,
MergeInventory,
)
from albert.resources.locations import Location
Expand Down Expand Up @@ -249,61 +251,153 @@ def get_by_ids(self, *, ids: list[InventoryId]) -> list[InventoryItem]:
return inventory

@validate_call
def get_specs(self, *, ids: list[InventoryId]) -> list[InventorySpecList]:
"""Get the specs for a list of inventory items.
def get_attributes(self, *, ids: list[InventoryId]) -> list[InventoryAttributeList]:
"""Get inventory attributes for a list of inventory items.

Parameters
----------
ids : list[InventoryId]
List of Inventory IDs to get the specs for.
List of Inventory IDs to get the attributes for.

Returns
-------
list[InventorySpecList]
A list of InventorySpecList entities, each containing the specs for an inventory item.
list[InventoryAttributeList]
A list of InventoryAttributeList entities, each containing the attributes for an inventory item.
"""
url = f"{self.base_path}/specs"
url = f"{self.base_path}/attributes"
batches = [ids[i : i + 250] for i in range(0, len(ids), 250)]
ta = TypeAdapter(InventorySpecList)
ta = TypeAdapter(InventoryAttributeList)
return [
ta.validate_python(item)
for batch in batches
for item in self.session.get(url, params={"id": batch}).json()
]

@validate_call
def add_specs(
def add_attributes(
self,
*,
inventory_id: InventoryId,
specs: InventorySpec | list[InventorySpec],
) -> InventorySpecList:
"""Add inventory specs to the inventory item.

An `InventorySpec` is a property that was not directly measured via a task,
but is a generic property of that inentory item.
attributes: InventoryAttribute | list[InventoryAttribute],
) -> InventoryAttributeList:
"""Add inventory attributes to the inventory item.

Parameters
----------
inventory_id : InventoryId
The Albert ID of the inventory item to add the specs to
specs : list[InventorySpec]
List of InventorySpec entities to add to the inventory item,
which described the value and, optionally,
the conditions associated with the value (via workflow).
The Albert ID of the inventory item to add attributes for.
attributes : list[InventoryAttribute]
List of InventoryAttribute entities to add for the inventory item.

Returns
-------
InventorySpecList
The list of InventorySpecs attached to the InventoryItem.
InventoryAttributeList
The list of InventoryAttributes attached to the InventoryItem.
"""
if isinstance(specs, InventorySpec):
specs = [specs]
if isinstance(attributes, InventoryAttribute):
attributes = [attributes]
response = self.session.put(
url=f"{self.base_path}/{inventory_id}/specs",
json=[x.model_dump(exclude_unset=True, by_alias=True, mode="json") for x in specs],
url=f"{self.base_path}/{inventory_id}/attributes",
json=[
x.model_dump(exclude_unset=True, by_alias=True, mode="json") for x in attributes
],
)
return InventorySpecList(**response.json())
return InventoryAttributeList(**response.json())

@validate_call
def update_attributes(
self,
*,
inventory_id: InventoryId,
updates: InventoryAttributeUpdate | list[InventoryAttributeUpdate],
) -> InventoryAttributeList:
"""Update inventory attribute values.

Parameters
----------
inventory_id : InventoryId
The Albert ID of the inventory item to update attributes for.
updates : list[InventoryAttributeUpdate]
The attribute updates to apply.

Returns
-------
InventoryAttributeList
The updated list of InventoryAttributes for the inventory item.
"""
if isinstance(updates, InventoryAttributeUpdate):
updates = [updates]
if not updates:
return self.get_attributes(ids=[inventory_id])[0]

payload: list[dict[str, object]] = []
for update in updates:
if update.reference_value is not None:
payload.append(
{
"operation": "update",
"attribute": "referenceValue",
"attributeId": update.attribute_id,
"newValue": update.reference_value,
}
)
if update.clear_reference_value:
payload.append(
{
"operation": "delete",
"attribute": "referenceValue",
"attributeId": update.attribute_id,
}
)
if update.range is not None:
payload.append(
{
"operation": "update",
"attribute": "range",
"attributeId": update.attribute_id,
"newValue": update.range.model_dump(
exclude_none=True,
by_alias=True,
mode="json",
),
}
)
if update.clear_range:
payload.append(
{
"operation": "delete",
"attribute": "range",
"attributeId": update.attribute_id,
}
)

if not payload:
return self.get_attributes(ids=[inventory_id])[0]

self.session.patch(
url=f"{self.base_path}/{inventory_id}/attributes",
json=payload,
)
return self.get_attributes(ids=[inventory_id])[0]

@validate_call
def delete_attribute(
self, *, inventory_id: InventoryId, attribute_id: ReferenceAttributeId
) -> None:
"""Delete an inventory attribute row by ID.

Parameters
----------
inventory_id : InventoryId
The Albert ID of the inventory item.
attribute_id : ReferenceAttributeId
The attribute ID to delete.

Returns
-------
None
"""
self.session.delete(f"{self.base_path}/{inventory_id}/attributes/{attribute_id}")

@validate_call
def delete(self, *, id: InventoryId) -> None:
Expand Down
Loading