albert 1.14.0__py3-none-any.whl → 1.16.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.
@@ -10,6 +10,7 @@ from albert.core.session import AlbertSession
10
10
  from albert.core.shared.enums import OrderBy, PaginationMode
11
11
  from albert.core.shared.identifiers import InventoryId, LotId, TaskId
12
12
  from albert.core.shared.models.patch import PatchDatum, PatchOperation, PatchPayload
13
+ from albert.core.utils import ensure_list
13
14
  from albert.resources.inventory import InventoryCategory
14
15
  from albert.resources.lots import Lot, LotSearchItem
15
16
 
@@ -188,39 +189,21 @@ class LotCollection(BaseCollection):
188
189
 
189
190
  search_text = text if (text is None or len(text) < 50) else text[:50]
190
191
 
191
- def _ensure_list(value):
192
- if value is None:
193
- return None
194
- if isinstance(value, list | tuple | set):
195
- return list(value)
196
- return [value]
197
-
198
- def _format_categories(value):
199
- raw = _ensure_list(value)
200
- if raw is None:
201
- return None
202
- formatted: list[str] = []
203
- for category in raw:
204
- formatted.append(
205
- category.value if isinstance(category, InventoryCategory) else category
206
- )
207
- return formatted
208
-
209
192
  params = {
210
193
  "offset": offset,
211
- "order": order_by.value,
194
+ "order": order_by,
212
195
  "text": search_text,
213
196
  "sortBy": sort_by,
214
197
  "isDropDown": is_drop_down,
215
- "inventoryId": _ensure_list(inventory_id),
216
- "locationId": _ensure_list(location_id),
217
- "storageLocationId": _ensure_list(storage_location_id),
218
- "taskId": _ensure_list(task_id),
219
- "category": _format_categories(category),
220
- "externalBarcodeId": _ensure_list(external_barcode_id),
221
- "searchField": _ensure_list(search_field),
222
- "sourceField": _ensure_list(source_field),
223
- "additionalField": _ensure_list(additional_field),
198
+ "inventoryId": ensure_list(inventory_id),
199
+ "locationId": ensure_list(location_id),
200
+ "storageLocationId": ensure_list(storage_location_id),
201
+ "taskId": ensure_list(task_id),
202
+ "category": ensure_list(category),
203
+ "externalBarcodeId": ensure_list(external_barcode_id),
204
+ "searchField": ensure_list(search_field),
205
+ "sourceField": ensure_list(source_field),
206
+ "additionalField": ensure_list(additional_field),
224
207
  }
225
208
  params = {key: value for key, value in params.items() if value is not None}
226
209
 
@@ -106,7 +106,7 @@ class NotesCollection(BaseCollection):
106
106
  """
107
107
  params = {
108
108
  "parentId": parent_id,
109
- "orderBy": order_by.value,
109
+ "orderBy": order_by,
110
110
  }
111
111
  response = self.session.get(
112
112
  url=self.base_path,
@@ -10,6 +10,7 @@ from albert.core.pagination import AlbertPaginator
10
10
  from albert.core.session import AlbertSession
11
11
  from albert.core.shared.enums import OrderBy, PaginationMode
12
12
  from albert.core.shared.identifiers import ParameterGroupId
13
+ from albert.core.utils import ensure_list
13
14
  from albert.exceptions import AlbertHTTPError
14
15
  from albert.resources.parameter_groups import (
15
16
  ParameterGroup,
@@ -97,9 +98,9 @@ class ParameterGroupCollection(BaseCollection):
97
98
  """
98
99
  params = {
99
100
  "offset": offset,
100
- "order": order_by.value,
101
+ "order": order_by,
101
102
  "text": text,
102
- "types": [types] if isinstance(types, PGType) else types,
103
+ "types": ensure_list(types),
103
104
  }
104
105
 
105
106
  return AlbertPaginator(
@@ -8,6 +8,7 @@ from albert.core.pagination import AlbertPaginator
8
8
  from albert.core.session import AlbertSession
9
9
  from albert.core.shared.enums import OrderBy, PaginationMode
10
10
  from albert.core.shared.identifiers import ParameterId
11
+ from albert.core.utils import ensure_list
11
12
  from albert.resources.parameters import Parameter
12
13
 
13
14
 
@@ -137,13 +138,12 @@ class ParameterCollection(BaseCollection):
137
138
  yield from (Parameter(**item) for item in items)
138
139
 
139
140
  params = {
140
- "orderBy": order_by.value,
141
+ "orderBy": order_by,
141
142
  "parameters": ids,
142
143
  "startKey": start_key,
143
144
  }
144
- if names:
145
- params["name"] = [names] if isinstance(names, str) else names
146
- params["exactMatch"] = exact_match
145
+ params["name"] = ensure_list(names)
146
+ params["exactMatch"] = exact_match
147
147
 
148
148
  return AlbertPaginator(
149
149
  mode=PaginationMode.KEY,
@@ -7,9 +7,9 @@ from albert.core.logging import logger
7
7
  from albert.core.pagination import AlbertPaginator
8
8
  from albert.core.session import AlbertSession
9
9
  from albert.core.shared.enums import OrderBy, PaginationMode
10
- from albert.core.shared.identifiers import ProjectId
10
+ from albert.core.shared.identifiers import ProjectId, SearchProjectId
11
11
  from albert.exceptions import AlbertHTTPError
12
- from albert.resources.projects import Project, ProjectSearchItem
12
+ from albert.resources.projects import DocumentSearchItem, Project, ProjectSearchItem
13
13
 
14
14
 
15
15
  class ProjectCollection(BaseCollection):
@@ -187,7 +187,7 @@ class ProjectCollection(BaseCollection):
187
187
  An iterator of matching partial (unhydrated) Project results.
188
188
  """
189
189
  query_params = {
190
- "order": order_by.value,
190
+ "order": order_by,
191
191
  "offset": offset,
192
192
  "text": text,
193
193
  "sortBy": sort_by,
@@ -219,6 +219,47 @@ class ProjectCollection(BaseCollection):
219
219
  ],
220
220
  )
221
221
 
222
+ @validate_call
223
+ def document_search(
224
+ self,
225
+ *,
226
+ linked_to: SearchProjectId,
227
+ text: str | None = None,
228
+ order_by: OrderBy = OrderBy.DESCENDING,
229
+ sort_by: str | None = None,
230
+ offset: int | None = None,
231
+ max_items: int | None = None,
232
+ ) -> Iterator[DocumentSearchItem]:
233
+ """Search for documents (attachments) linked to a project.
234
+
235
+ Args:
236
+ linked_to: The project ID to filter documents by (e.g. "P770").
237
+ text: Full-text search query for document names.
238
+ order_by: Sort order. Default is DESCENDING.
239
+ sort_by: Field to sort by (e.g. "createdAt").
240
+ offset: Pagination offset.
241
+ max_items: Maximum number of items to return. If None, fetches all.
242
+
243
+ Returns:
244
+ An iterator of DocumentSearchItem results.
245
+ """
246
+ query_params = {
247
+ "linkedTo": linked_to,
248
+ "text": text,
249
+ "order": order_by,
250
+ "sortBy": sort_by,
251
+ "offset": offset,
252
+ }
253
+
254
+ return AlbertPaginator(
255
+ mode=PaginationMode.OFFSET,
256
+ path=f"{self.base_path}/documentsearch",
257
+ session=self.session,
258
+ params=query_params,
259
+ max_items=max_items,
260
+ deserialize=lambda items: [DocumentSearchItem(**item) for item in items],
261
+ )
262
+
222
263
  @validate_call
223
264
  def get_all(
224
265
  self,
@@ -1,6 +1,5 @@
1
1
  from collections.abc import Iterator
2
2
  from contextlib import suppress
3
- from enum import Enum
4
3
 
5
4
  import pandas as pd
6
5
  from pydantic import validate_call
@@ -23,6 +22,7 @@ from albert.core.shared.identifiers import (
23
22
  UserId,
24
23
  )
25
24
  from albert.core.shared.models.patch import PatchOperation
25
+ from albert.core.utils import ensure_list
26
26
  from albert.exceptions import NotFoundError
27
27
  from albert.resources.property_data import (
28
28
  BulkPropertyData,
@@ -1086,22 +1086,19 @@ class PropertyDataCollection(BaseCollection):
1086
1086
  def deserialize(items: list[dict]) -> list[PropertyDataSearchItem]:
1087
1087
  return [PropertyDataSearchItem.model_validate(x) for x in items]
1088
1088
 
1089
- def ensure_list(v):
1090
- if v is None:
1091
- return None
1092
- return [v] if isinstance(v, str | Enum) else v
1089
+ category_values = ensure_list(category)
1093
1090
 
1094
1091
  params = {
1095
1092
  "result": result,
1096
1093
  "text": text,
1097
- "order": order.value if order else None,
1094
+ "order": order,
1098
1095
  "sortBy": sort_by,
1099
1096
  "inventoryIds": ensure_list(inventory_ids),
1100
1097
  "projectIds": ensure_list(project_ids),
1101
1098
  "lotIds": ensure_list(lot_ids),
1102
1099
  "dataTemplateId": ensure_list(data_template_ids),
1103
1100
  "dataColumnId": ensure_list(data_column_ids),
1104
- "category": [c.value for c in ensure_list(category)] if category else None,
1101
+ "category": category_values if category_values else None,
1105
1102
  "dataTemplates": ensure_list(data_templates),
1106
1103
  "dataColumns": ensure_list(data_columns),
1107
1104
  "parameters": ensure_list(parameters),
@@ -7,6 +7,7 @@ from albert.core.pagination import AlbertPaginator
7
7
  from albert.core.session import AlbertSession
8
8
  from albert.core.shared.enums import PaginationMode
9
9
  from albert.core.shared.models.base import EntityLink
10
+ from albert.core.utils import ensure_list
10
11
  from albert.exceptions import AlbertHTTPError
11
12
  from albert.resources.locations import Location
12
13
  from albert.resources.storage_locations import StorageLocation
@@ -93,9 +94,8 @@ class StorageLocationsCollection(BaseCollection):
93
94
  "startKey": start_key,
94
95
  }
95
96
 
96
- if name:
97
- params["name"] = [name] if isinstance(name, str) else name
98
- params["exactMatch"] = exact_match
97
+ params["name"] = ensure_list(name)
98
+ params["exactMatch"] = exact_match
99
99
 
100
100
  return AlbertPaginator(
101
101
  mode=PaginationMode.KEY,
@@ -9,6 +9,7 @@ from albert.core.pagination import AlbertPaginator
9
9
  from albert.core.session import AlbertSession
10
10
  from albert.core.shared.enums import OrderBy, PaginationMode
11
11
  from albert.core.shared.identifiers import TagId
12
+ from albert.core.utils import ensure_list
12
13
  from albert.exceptions import AlbertException
13
14
  from albert.resources.tags import Tag
14
15
 
@@ -258,12 +259,12 @@ class TagCollection(BaseCollection):
258
259
  An iterator of Tag entities matching the filters.
259
260
  """
260
261
  params = {
261
- "orderBy": order_by.value,
262
+ "orderBy": order_by,
262
263
  "startKey": start_key,
263
264
  }
264
265
 
265
266
  if name:
266
- params["name"] = [name] if isinstance(name, str) else name
267
+ params["name"] = ensure_list(name)
267
268
  params["exactMatch"] = exact_match
268
269
 
269
270
  return AlbertPaginator(
@@ -25,6 +25,7 @@ from albert.core.shared.identifiers import (
25
25
  WorkflowId,
26
26
  remove_id_prefix,
27
27
  )
28
+ from albert.core.utils import ensure_list
28
29
  from albert.exceptions import AlbertHTTPError
29
30
  from albert.resources.attachments import AttachmentCategory
30
31
  from albert.resources.data_templates import ImportMode
@@ -570,13 +571,12 @@ class TaskCollection(BaseCollection):
570
571
 
571
572
  params = {
572
573
  "offset": offset,
573
- "order": order_by.value,
574
+ "order": order_by,
574
575
  "text": text,
575
576
  "sortBy": sort_by,
576
577
  "tags": tags,
577
578
  "taskId": task_id,
578
579
  "linkedTask": linked_task,
579
- "category": category,
580
580
  "albertId": albert_id,
581
581
  "dataTemplate": data_template,
582
582
  "assignedTo": assigned_to,
@@ -588,6 +588,9 @@ class TaskCollection(BaseCollection):
588
588
  "projectId": project_id,
589
589
  }
590
590
 
591
+ category_values = ensure_list(category)
592
+ params["category"] = category_values if category_values else None
593
+
591
594
  return AlbertPaginator(
592
595
  mode=PaginationMode.OFFSET,
593
596
  path=f"{self.base_path}/search",
@@ -749,7 +752,7 @@ class TaskCollection(BaseCollection):
749
752
  """Fetch the audit history for the specified task."""
750
753
  params = {
751
754
  "limit": limit,
752
- "orderBy": OrderBy(order).value if order else None,
755
+ "orderBy": order,
753
756
  "entity": entity,
754
757
  "blockId": blockId,
755
758
  "startKey": startKey,
@@ -8,6 +8,7 @@ from albert.core.pagination import AlbertPaginator
8
8
  from albert.core.session import AlbertSession
9
9
  from albert.core.shared.enums import OrderBy, PaginationMode
10
10
  from albert.core.shared.identifiers import UnitId
11
+ from albert.core.utils import ensure_list
11
12
  from albert.resources.units import Unit, UnitCategory
12
13
 
13
14
 
@@ -192,11 +193,11 @@ class UnitCollection(BaseCollection):
192
193
  An iterator of Unit entities.
193
194
  """
194
195
  params = {
195
- "orderBy": order_by.value,
196
- "name": [name] if isinstance(name, str) else name,
196
+ "orderBy": order_by,
197
+ "name": ensure_list(name),
197
198
  "exactMatch": exact_match,
198
199
  "verified": verified,
199
- "category": category.value if isinstance(category, UnitCategory) else category,
200
+ "category": category,
200
201
  "startKey": start_key,
201
202
  }
202
203
 
@@ -135,7 +135,7 @@ class UserCollection(BaseCollection):
135
135
  params = {
136
136
  "text": text,
137
137
  "sortBy": sort_by,
138
- "order": order_by.value,
138
+ "order": order_by,
139
139
  "roles": roles,
140
140
  "teams": teams,
141
141
  "locations": locations,
@@ -198,7 +198,7 @@ class UserCollection(BaseCollection):
198
198
  """
199
199
  params = {
200
200
  "status": status,
201
- "type": type.value if type else None,
201
+ "type": type,
202
202
  "id": id,
203
203
  "startKey": start_key,
204
204
  }
albert/core/utils.py ADDED
@@ -0,0 +1,20 @@
1
+ """Utility helpers shared across Albert SDK modules."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from typing import TypeVar
7
+
8
+ T = TypeVar("T")
9
+
10
+
11
+ def ensure_list(value: T | Iterable[T] | None) -> list[T] | None:
12
+ """Return ``value`` as a list, preserving ``None`` and existing lists."""
13
+
14
+ if value is None:
15
+ return None
16
+ if isinstance(value, list):
17
+ return value
18
+ if isinstance(value, tuple | set):
19
+ return list(value)
20
+ return [value]
@@ -5,7 +5,7 @@ from pydantic import Field, model_validator
5
5
 
6
6
  from albert.core.base import BaseAlbertModel
7
7
  from albert.core.shared.enums import SecurityClass, Status
8
- from albert.core.shared.identifiers import CustomTemplateId, NotebookId
8
+ from albert.core.shared.identifiers import CustomTemplateId, EntityTypeId, NotebookId
9
9
  from albert.core.shared.models.base import BaseResource, EntityLink
10
10
  from albert.core.shared.types import MetadataItem, SerializeAsEntityLink
11
11
  from albert.resources._mixins import HydrationMixin
@@ -19,16 +19,27 @@ from albert.resources.tasks import TaskSource
19
19
  from albert.resources.users import User, UserClass
20
20
 
21
21
 
22
+ class CustomTemplateInventoryLot(BaseAlbertModel):
23
+ id: str
24
+ barcode: str | None = None
25
+
26
+
22
27
  class DataTemplateInventory(EntityLink):
23
28
  batch_size: float | None = Field(default=None, alias="batchSize")
24
29
  sheet: list[Sheet | EntityLink] | None = Field(default=None)
25
30
  category: InventoryCategory | None = Field(default=None)
31
+ lots: list[CustomTemplateInventoryLot] | None = Field(default=None, alias="Lots")
26
32
 
27
33
 
28
34
  class DesignLink(EntityLink):
29
35
  type: DesignType
30
36
 
31
37
 
38
+ class TemplateEntityType(BaseAlbertModel):
39
+ id: EntityTypeId | None = Field(default=None)
40
+ custom_category: str | None = Field(default=None, alias="customCategory")
41
+
42
+
32
43
  class TemplateCategory(str, Enum):
33
44
  PROPERTY_LIST = "Property Task"
34
45
  PROPERTY = "Property"
@@ -55,6 +66,7 @@ class GeneralData(BaseTaggedResource):
55
66
  priority: Priority | None = Field(default=None)
56
67
  sources: list[TaskSource] | None = Field(alias="Sources", default=None)
57
68
  parent_id: str | None = Field(alias="parentId", default=None)
69
+ metadata: dict[str, MetadataItem] | None = Field(default=None, alias="Metadata")
58
70
 
59
71
 
60
72
  class JobStatus(str, Enum):
@@ -79,7 +91,7 @@ class SamConfig(BaseResource):
79
91
 
80
92
  class Workflow(BaseResource):
81
93
  id: str
82
- name: str
94
+ name: str | None = Field(default=None)
83
95
  # Some workflows may have SamConfig
84
96
  sam_config: list[SamConfig] | None = Field(default=None, alias="SamConfig")
85
97
 
@@ -176,7 +188,7 @@ class TemplateACL(BaseResource):
176
188
  acl_class: str | None = Field(default=None, alias="class")
177
189
 
178
190
 
179
- class CustomTemplate(BaseTaggedResource):
191
+ class CustomTemplate(BaseTaggedResource, HydrationMixin["CustomTemplate"]):
180
192
  """A custom template entity.
181
193
 
182
194
  Attributes
@@ -186,11 +198,15 @@ class CustomTemplate(BaseTaggedResource):
186
198
  id : str
187
199
  The Albert ID of the template. Set when the template is retrieved from Albert.
188
200
  category : TemplateCategory
189
- The category of the template. Allowed values are `Property Task`, `Property`, `Batch`, `Sheet`, `Notebook`, and `General`.
201
+ The category of the template.
190
202
  metadata : Dict[str, str | List[EntityLink] | EntityLink] | None
191
203
  The metadata of the template. Allowed Metadata fields can be found using Custim Fields.
192
204
  data : CustomTemplateData | None
193
205
  The data of the template.
206
+ entity_type : TemplateEntityType | None
207
+ The entity type associated with the template.
208
+ locked : bool | None
209
+ Whether the template is locked when loaded in the UI.
194
210
  team : List[TeamACL] | None
195
211
  The team of the template.
196
212
  acl : TemplateACL | None
@@ -198,10 +214,12 @@ class CustomTemplate(BaseTaggedResource):
198
214
  """
199
215
 
200
216
  name: str
201
- id: CustomTemplateId = Field(alias="albertId")
217
+ id: CustomTemplateId | None = Field(default=None, alias="albertId")
202
218
  category: TemplateCategory = Field(default=TemplateCategory.GENERAL)
203
219
  metadata: dict[str, MetadataItem] | None = Field(default=None, alias="Metadata")
204
220
  data: CustomTemplateData | None = Field(default=None, alias="Data")
221
+ entity_type: TemplateEntityType | None = Field(default=None, alias="EntityType")
222
+ locked: bool | None = Field(default=None)
205
223
  team: list[TeamACL] | None = Field(default_factory=list)
206
224
  acl: TemplateACL | None = Field(default_factory=list, alias="ACL")
207
225
 
@@ -211,9 +229,13 @@ class CustomTemplate(BaseTaggedResource):
211
229
  """
212
230
  Initialize private attributes from the incoming data dictionary before the model is fully constructed.
213
231
  """
232
+ if not isinstance(data, dict):
233
+ return data
214
234
 
215
- if "Data" in data and "category" in data and "category" not in data["Data"]:
216
- data["Data"]["category"] = data["category"]
235
+ data_payload = data.get("Data")
236
+ category = data.get("category")
237
+ if isinstance(data_payload, dict) and category is not None:
238
+ data_payload.setdefault("category", category)
217
239
  return data
218
240
 
219
241
 
@@ -241,9 +263,9 @@ class CustomTemplateSearchItem(BaseAlbertModel, HydrationMixin[CustomTemplate]):
241
263
  id: CustomTemplateId = Field(alias="albertId")
242
264
  created_by_name: str = Field(..., alias="createdByName")
243
265
  created_at: str = Field(..., alias="createdAt")
244
- category: str
266
+ category: str | None = None
245
267
  status: Status | None = None
246
268
  resource_class: SecurityClass | None = Field(default=None, alias="resourceClass")
247
269
  data: CustomTemplateSearchItemData | None = None
248
- acl: list[CustomTemplateSearchItemACL]
249
- team: list[CustomTemplateSearchItemTeam]
270
+ acl: list[CustomTemplateSearchItemACL] | None = None
271
+ team: list[CustomTemplateSearchItemTeam] | None = None
@@ -3,7 +3,7 @@ from enum import Enum
3
3
  from pydantic import Field, field_validator
4
4
 
5
5
  from albert.core.base import BaseAlbertModel
6
- from albert.core.shared.identifiers import ProjectId
6
+ from albert.core.shared.identifiers import AttachmentId, ProjectId
7
7
  from albert.core.shared.models.base import BaseResource
8
8
  from albert.core.shared.types import MetadataItem, SerializeAsEntityLink
9
9
  from albert.resources._mixins import HydrationMixin
@@ -110,3 +110,18 @@ class ProjectSearchItem(BaseAlbertModel, HydrationMixin[Project]):
110
110
  id: ProjectId | None = Field(None, alias="albertId")
111
111
  description: str = Field(min_length=1, max_length=2000)
112
112
  status: str | None = Field(default=None, exclude=True, frozen=True)
113
+
114
+
115
+ class DocumentSearchItem(BaseAlbertModel):
116
+ """A document (attachment) search result item from a project."""
117
+
118
+ id: AttachmentId | None = Field(None, alias="albertId")
119
+ name: str | None = None
120
+ mime_type: str | None = Field(default=None, alias="mimeType")
121
+ file_size: int | None = Field(default=None, alias="fileSize")
122
+ project_id: str | None = Field(default=None, alias="projectId")
123
+ key: str | None = None
124
+ source: str | None = None
125
+ created_by: str | None = Field(default=None, alias="createdBy")
126
+ created_by_name: str | None = Field(default=None, alias="createdByName")
127
+ created_at: str | None = Field(default=None, alias="createdAt")
albert/resources/tags.py CHANGED
@@ -1,13 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from enum import Enum
4
- from typing import Any
5
4
 
6
- from pydantic import AliasChoices, Field, model_validator
5
+ from pydantic import AliasChoices, Field
7
6
 
8
- from albert.core.logging import logger
9
7
  from albert.core.shared.models.base import BaseResource
10
- from albert.core.shared.types import SerializeAsEntityLink
11
8
 
12
9
 
13
10
  class TagEntity(str, Enum):
@@ -62,40 +59,3 @@ class Tag(BaseResource):
62
59
  The Tag object created from the string.
63
60
  """
64
61
  return cls(tag=tag)
65
-
66
-
67
- class BaseTaggedEntity(BaseResource):
68
- """
69
- BaseTaggedEntity is a Pydantic model that includes functionality for handling tags as either Tag objects or strings.
70
-
71
- Attributes
72
- ----------
73
- tags : List[Tag | str] | None
74
- A list of Tag objects or strings representing tags.
75
- """
76
-
77
- tags: list[SerializeAsEntityLink[Tag]] | None = Field(None, alias="Tags")
78
-
79
- @model_validator(mode="before") # must happen before to keep type validation
80
- @classmethod
81
- def convert_tags(cls, data: dict[str, Any]) -> dict[str, Any]:
82
- if not isinstance(data, dict):
83
- return data
84
- tags = data.get("tags")
85
- if not tags:
86
- tags = data.get("Tags")
87
- if tags:
88
- new_tags = []
89
- for t in tags:
90
- if isinstance(t, Tag):
91
- new_tags.append(t)
92
- elif isinstance(t, str):
93
- new_tags.append(Tag.from_string(t))
94
- elif isinstance(t, dict):
95
- new_tags.append(Tag(**t))
96
- else:
97
- # We do not expect this else to be hit because tags should only be Tag or str
98
- logger.warning(f"Unexpected value for Tag. {t} of type {type(t)}")
99
- continue
100
- data["tags"] = new_tags
101
- return data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: albert
3
- Version: 1.14.0
3
+ Version: 1.16.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