albert 1.12.0__py3-none-any.whl → 1.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
albert/__init__.py CHANGED
@@ -4,4 +4,4 @@ from albert.core.auth.sso import AlbertSSOClient
4
4
 
5
5
  __all__ = ["Albert", "AlbertClientCredentials", "AlbertSSOClient"]
6
6
 
7
- __version__ = "1.12.0"
7
+ __version__ = "1.13.0"
@@ -14,6 +14,7 @@ from albert.resources._mixins import HydrationMixin
14
14
  from albert.resources.acls import ACL
15
15
  from albert.resources.cas import Cas
16
16
  from albert.resources.companies import Company
17
+ from albert.resources.lists import ListItem
17
18
  from albert.resources.locations import Location
18
19
  from albert.resources.tagged_base import BaseTaggedResource
19
20
  from albert.resources.tags import Tag
@@ -75,6 +76,8 @@ class CasAmount(BaseAlbertModel):
75
76
  The SMILES string of the CAS Number resource. Obtained from the Cas object when provided.
76
77
  number: str | None
77
78
  The CAS number. Obtained from the Cas object when provided.
79
+ inventory_function: list[ListItem | EntityLink | str] | None
80
+ Business-controlled functions associated with the CAS in this inventory context.
78
81
 
79
82
  !!! tip
80
83
  ---
@@ -87,6 +90,9 @@ class CasAmount(BaseAlbertModel):
87
90
  target: float | None = Field(default=None, alias="inventoryValue")
88
91
  id: str | None = Field(default=None)
89
92
  cas_category: str | None = Field(default=None, alias="casCategory")
93
+ inventory_function: list[SerializeAsEntityLink[ListItem] | str] | None = Field(
94
+ default=None, alias="inventoryFunction"
95
+ )
90
96
  type: str | None = Field(default=None)
91
97
  classification_type: str | None = Field(default=None, alias="classificationType")
92
98
 
albert/resources/lists.py CHANGED
@@ -25,9 +25,11 @@ class ListItem(BaseResource):
25
25
  id : str | None
26
26
  The Albert ID of the list item. Set when the list item is retrieved from Albert.
27
27
  category : ListItemCategory | None
28
- The category of the list item. Allowed values are `businessDefined`, `userDefined`, `projects`, and `extensions`.
28
+ The category of the list item. Allowed values are `businessDefined`, `userDefined`, `projects`, `extensions`,
29
+ and `inventory`.
29
30
  list_type : str | None
30
- The type of the list item. Allowed values are `projectState` for `projects` and `extensions` for `extensions`.
31
+ The type of the list item. Allowed values are `projectState` for `projects`, `extensions` for `extensions`,
32
+ and `casCategory` or `inventoryFunction` for `inventory`.
31
33
  """
32
34
 
33
35
  name: str
@@ -37,14 +39,15 @@ class ListItem(BaseResource):
37
39
 
38
40
  @model_validator(mode="after")
39
41
  def validate_list_type(self) -> ListItem:
42
+ allowed_by_category = {
43
+ ListItemCategory.PROJECTS: {"projectState"},
44
+ ListItemCategory.EXTENSIONS: {"extensions"},
45
+ ListItemCategory.INVENTORY: {"casCategory", "inventoryFunction"},
46
+ }
40
47
  if (
41
- self.category == ListItemCategory.PROJECTS
42
- and self.list_type is not None
43
- and self.list_type != "projectState"
44
- ) or (
45
- self.category == ListItemCategory.EXTENSIONS
46
- and self.list_type is not None
47
- and self.list_type != "extensions"
48
+ self.list_type is not None
49
+ and self.category in allowed_by_category
50
+ and self.list_type not in allowed_by_category[self.category]
48
51
  ):
49
52
  raise ValueError(
50
53
  f"List type {self.list_type} is not allowed for category {self.category}"
albert/utils/inventory.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from collections.abc import Iterable
2
2
  from typing import Any
3
3
 
4
+ from albert.core.shared.models.base import BaseResource, EntityLink
4
5
  from albert.resources.inventory import CasAmount
5
6
 
6
7
 
@@ -56,6 +57,61 @@ def _build_cas_delete_operation(identifier: str) -> dict[str, Any]:
56
57
  }
57
58
 
58
59
 
60
+ def _normalize_inventory_function_ids(
61
+ value: list[BaseResource | EntityLink | str] | None,
62
+ ) -> list[str]:
63
+ if not value:
64
+ return []
65
+ ids: list[str] = []
66
+ for item in value:
67
+ if isinstance(item, str):
68
+ if item:
69
+ ids.append(item)
70
+ continue
71
+ if isinstance(item, BaseResource):
72
+ if item.id:
73
+ ids.append(item.id)
74
+ continue
75
+ if isinstance(item, EntityLink):
76
+ if item.id:
77
+ ids.append(item.id)
78
+ continue
79
+ return ids
80
+
81
+
82
+ def _build_inventory_function_operations(
83
+ *,
84
+ entity_id: str,
85
+ existing: list[BaseResource | EntityLink | str] | None,
86
+ updated: list[BaseResource | EntityLink | str] | None,
87
+ ) -> list[dict[str, Any]]:
88
+ existing_ids = set(_normalize_inventory_function_ids(existing))
89
+ updated_ids = set(_normalize_inventory_function_ids(updated))
90
+ to_add = sorted(updated_ids - existing_ids)
91
+ to_delete = sorted(existing_ids - updated_ids)
92
+
93
+ operations: list[dict[str, Any]] = []
94
+ if to_add:
95
+ operations.append(
96
+ {
97
+ "attribute": "inventoryFunction",
98
+ "entityId": entity_id,
99
+ "operation": "add",
100
+ "newValue": to_add,
101
+ }
102
+ )
103
+ if to_delete:
104
+ operations.append(
105
+ {
106
+ "attribute": "inventoryFunction",
107
+ "entityId": entity_id,
108
+ "operation": "delete",
109
+ "oldValue": to_delete,
110
+ }
111
+ )
112
+ return operations
113
+
114
+
59
115
  def _build_cas_scalar_operation(
60
116
  *,
61
117
  attribute: str,
@@ -117,6 +173,14 @@ def _build_cas_update_operations(existing: CasAmount, updated: CasAmount) -> lis
117
173
  if operation is not None:
118
174
  operations.append(operation)
119
175
 
176
+ operations.extend(
177
+ _build_inventory_function_operations(
178
+ entity_id=identifier,
179
+ existing=existing.inventory_function,
180
+ updated=updated.inventory_function,
181
+ )
182
+ )
183
+
120
184
  return operations
121
185
 
122
186
 
@@ -159,6 +223,13 @@ def _build_cas_patch_operations(
159
223
  )
160
224
  if target_operation is not None:
161
225
  operations.append(target_operation)
226
+ operations.extend(
227
+ _build_inventory_function_operations(
228
+ entity_id=identifier,
229
+ existing=None,
230
+ updated=cas_amount.inventory_function,
231
+ )
232
+ )
162
233
 
163
234
  removals = [existing_lookup[key] for key in existing_lookup.keys() - updated_lookup.keys()]
164
235
  for cas_amount in removals:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: albert
3
- Version: 1.12.0
3
+ Version: 1.13.0
4
4
  Summary: The official Python SDK for the Albert Invent platform.
5
5
  Project-URL: Homepage, https://www.albertinvent.com/
6
6
  Project-URL: Documentation, https://docs.developer.albertinvent.com/albert-python
@@ -1,4 +1,4 @@
1
- albert/__init__.py,sha256=IxZK2r9lTXpOpps67inCsmcTp1mEgdAXXsoIgn-EO2c,239
1
+ albert/__init__.py,sha256=GFvvmokCWEGy95K7pNqV4Rme5Dfut9E7_lnKxNTtL1o,239
2
2
  albert/client.py,sha256=9SUy9AJpnFEUlSfxvbP1gJI776WcOoZykgPHx0EcF8g,12038
3
3
  albert/exceptions.py,sha256=-oxOJGE0A__aPUhri3qqb5YQ5qanECcTqamS73vGajM,3172
4
4
  albert/collections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -80,9 +80,9 @@ albert/resources/entity_types.py,sha256=7lessP8StBDfi4DZMifvRNN4lspdQ5X0olBIu7lT
80
80
  albert/resources/facet.py,sha256=tjm6CsOL7T5LSV4G9406C1c5mpzY1gpfQYAttP6Hckw,372
81
81
  albert/resources/files.py,sha256=0q5H6rJ9il0Oy1FnwxVo3otq_w8YQeQjo29DgsTY8JQ,1067
82
82
  albert/resources/hazards.py,sha256=ltlbYct3PhvpTojqic0OcfJVKd2s6m59XqszzZZAuWo,375
83
- albert/resources/inventory.py,sha256=f0f8WGEGbbDgXUe9FoipsVsEmJkeuIKEId0WuEV_QXc,13608
83
+ albert/resources/inventory.py,sha256=xkPZDOR-KFB79We56K4A35Td_L3kqe2OJ8Tvzrj1vQE,13944
84
84
  albert/resources/links.py,sha256=te7KIO7vfXrA-Qjngvb4JHy--SUVTG5M7GBFz8XdKto,1032
85
- albert/resources/lists.py,sha256=-ViW_wHJbaQh47zXNr1eszOMmwSFX-nQWTfOA8BzOG8,1687
85
+ albert/resources/lists.py,sha256=UinEaBEEo80Q1Vf5Ys4ViPcNTSvAeCRaZiW41CHY4f0,1861
86
86
  albert/resources/locations.py,sha256=xqbSoO-IjLSyK74W1jSdsNL9kUN5jD6Wf9XNxw8czYA,821
87
87
  albert/resources/lots.py,sha256=8YC6fHv08uYvhh09ULzNtFmdyfLeM1z6Hkm9wcTvcX4,6839
88
88
  albert/resources/notebooks.py,sha256=PebrXEbR8J9afqwwTwGjFlEkYCdqRh3AtvVwYMypex8,9581
@@ -114,10 +114,10 @@ albert/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
114
  albert/utils/_auth.py,sha256=YjzaGIzI9qP53nwdyE2Ezs-9UokzA38kgdE7Sxnyjd8,124
115
115
  albert/utils/_patch.py,sha256=e-bD2x6W3Wt4FaKFK477h3kZeyucn3DEB9m5DR7LzaA,24273
116
116
  albert/utils/data_template.py,sha256=AUwzfQ-I2HY-osq_Tme5KLwXfMzW2pJpiud7HAMh148,27874
117
- albert/utils/inventory.py,sha256=ViHxb62DVxniEJqOfD7Gf8HltLeCbq21y4rS1xkVRnY,5349
117
+ albert/utils/inventory.py,sha256=hhL1wCn2vtF2z5FGwlX-3XIla4paB26QbmbStkG3yTQ,7433
118
118
  albert/utils/property_data.py,sha256=xb0CZAh_0zFiN5yQwcw3Mjk4En8MxMrJF9DKQI19UhM,25074
119
119
  albert/utils/tasks.py,sha256=ejhXD9yQR_ReDKLJ3k8ZxWxkYl-Mta_4OPXrz_lQiBI,19878
120
- albert-1.12.0.dist-info/METADATA,sha256=fPc1wDNv8rwCKP4RMRMyrmEx9-tShO2r8UuRPMr7yw0,15427
121
- albert-1.12.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
122
- albert-1.12.0.dist-info/licenses/LICENSE,sha256=S7_vRdIhQmG7PmTlU8-BCCveuEcFZ6_3IUVdcoaJMuA,11348
123
- albert-1.12.0.dist-info/RECORD,,
120
+ albert-1.13.0.dist-info/METADATA,sha256=9QEz1ieKLpVnsyjDhJdyfZ0BfYZOpn6aJAP-3vdYCAU,15427
121
+ albert-1.13.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
122
+ albert-1.13.0.dist-info/licenses/LICENSE,sha256=S7_vRdIhQmG7PmTlU8-BCCveuEcFZ6_3IUVdcoaJMuA,11348
123
+ albert-1.13.0.dist-info/RECORD,,