albert 1.14.1__tar.gz → 1.16.0__tar.gz

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.
Files changed (303) hide show
  1. albert-1.16.0/.github/workflows/release-please.yml +19 -0
  2. albert-1.16.0/.release-please-manifest.json +1 -0
  3. {albert-1.14.1 → albert-1.16.0}/CHANGELOG.md +19 -0
  4. {albert-1.14.1 → albert-1.16.0}/PKG-INFO +1 -1
  5. albert-1.16.0/release-please-config.json +10 -0
  6. {albert-1.14.1 → albert-1.16.0}/src/albert/__init__.py +1 -1
  7. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/attachments.py +45 -1
  8. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/btinsight.py +9 -8
  9. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/cas.py +1 -1
  10. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/companies.py +3 -3
  11. albert-1.16.0/src/albert/collections/custom_templates.py +414 -0
  12. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/data_columns.py +4 -3
  13. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/data_templates.py +1 -1
  14. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/entity_types.py +2 -2
  15. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/inventory.py +8 -8
  16. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/lists.py +1 -1
  17. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/locations.py +3 -3
  18. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/lots.py +11 -28
  19. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/notes.py +1 -1
  20. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/parameter_groups.py +3 -2
  21. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/parameters.py +4 -4
  22. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/projects.py +44 -3
  23. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/property_data.py +4 -7
  24. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/storage_locations.py +3 -3
  25. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/tags.py +3 -2
  26. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/tasks.py +6 -3
  27. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/units.py +4 -3
  28. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/users.py +2 -2
  29. albert-1.16.0/src/albert/core/utils.py +20 -0
  30. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/custom_templates.py +32 -10
  31. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/projects.py +16 -1
  32. albert-1.16.0/src/albert/resources/tags.py +61 -0
  33. albert-1.16.0/tests/collections/test_custom_templates.py +99 -0
  34. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_inventory.py +7 -25
  35. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_projects.py +22 -1
  36. {albert-1.14.1 → albert-1.16.0}/tests/conftest.py +47 -0
  37. albert-1.14.1/src/albert/collections/custom_templates.py +0 -125
  38. albert-1.14.1/src/albert/resources/tags.py +0 -101
  39. albert-1.14.1/tests/collections/test_custom_templates.py +0 -60
  40. {albert-1.14.1 → albert-1.16.0}/.circleci/config.yml +0 -0
  41. {albert-1.14.1 → albert-1.16.0}/.gitignore +0 -0
  42. {albert-1.14.1 → albert-1.16.0}/.pre-commit-config.yaml +0 -0
  43. {albert-1.14.1 → albert-1.16.0}/.vscode/settings.json +0 -0
  44. {albert-1.14.1 → albert-1.16.0}/AGENTS.md +0 -0
  45. {albert-1.14.1 → albert-1.16.0}/CONTRIBUTING.md +0 -0
  46. {albert-1.14.1 → albert-1.16.0}/LICENSE +0 -0
  47. {albert-1.14.1 → albert-1.16.0}/README.md +0 -0
  48. {albert-1.14.1 → albert-1.16.0}/docs/CONTRIBUTING.md +0 -0
  49. {albert-1.14.1 → albert-1.16.0}/docs/albert.md +0 -0
  50. {albert-1.14.1 → albert-1.16.0}/docs/assets/Albert_Wordmark_Mono_RGB_White.svg +0 -0
  51. {albert-1.14.1 → albert-1.16.0}/docs/assets/Albert_Wordmark_RGB_Colour.svg +0 -0
  52. {albert-1.14.1 → albert-1.16.0}/docs/assets/favicon_bw.svg +0 -0
  53. {albert-1.14.1 → albert-1.16.0}/docs/authentication.md +0 -0
  54. {albert-1.14.1 → albert-1.16.0}/docs/collections/activities.md +0 -0
  55. {albert-1.14.1 → albert-1.16.0}/docs/collections/attachments.md +0 -0
  56. {albert-1.14.1 → albert-1.16.0}/docs/collections/base.md +0 -0
  57. {albert-1.14.1 → albert-1.16.0}/docs/collections/batch_data.md +0 -0
  58. {albert-1.14.1 → albert-1.16.0}/docs/collections/btdataset.md +0 -0
  59. {albert-1.14.1 → albert-1.16.0}/docs/collections/btinsight.md +0 -0
  60. {albert-1.14.1 → albert-1.16.0}/docs/collections/btmodel.md +0 -0
  61. {albert-1.14.1 → albert-1.16.0}/docs/collections/cas.md +0 -0
  62. {albert-1.14.1 → albert-1.16.0}/docs/collections/companies.md +0 -0
  63. {albert-1.14.1 → albert-1.16.0}/docs/collections/custom_fields.md +0 -0
  64. {albert-1.14.1 → albert-1.16.0}/docs/collections/custom_templates.md +0 -0
  65. {albert-1.14.1 → albert-1.16.0}/docs/collections/data_columns.md +0 -0
  66. {albert-1.14.1 → albert-1.16.0}/docs/collections/data_templates.md +0 -0
  67. {albert-1.14.1 → albert-1.16.0}/docs/collections/entity_types.md +0 -0
  68. {albert-1.14.1 → albert-1.16.0}/docs/collections/files.md +0 -0
  69. {albert-1.14.1 → albert-1.16.0}/docs/collections/hazards.md +0 -0
  70. {albert-1.14.1 → albert-1.16.0}/docs/collections/inventory.md +0 -0
  71. {albert-1.14.1 → albert-1.16.0}/docs/collections/links.md +0 -0
  72. {albert-1.14.1 → albert-1.16.0}/docs/collections/lists.md +0 -0
  73. {albert-1.14.1 → albert-1.16.0}/docs/collections/locations.md +0 -0
  74. {albert-1.14.1 → albert-1.16.0}/docs/collections/lots.md +0 -0
  75. {albert-1.14.1 → albert-1.16.0}/docs/collections/notebooks.md +0 -0
  76. {albert-1.14.1 → albert-1.16.0}/docs/collections/notes.md +0 -0
  77. {albert-1.14.1 → albert-1.16.0}/docs/collections/parameter_groups.md +0 -0
  78. {albert-1.14.1 → albert-1.16.0}/docs/collections/parameters.md +0 -0
  79. {albert-1.14.1 → albert-1.16.0}/docs/collections/pricings.md +0 -0
  80. {albert-1.14.1 → albert-1.16.0}/docs/collections/product_design.md +0 -0
  81. {albert-1.14.1 → albert-1.16.0}/docs/collections/projects.md +0 -0
  82. {albert-1.14.1 → albert-1.16.0}/docs/collections/property_data.md +0 -0
  83. {albert-1.14.1 → albert-1.16.0}/docs/collections/reports.md +0 -0
  84. {albert-1.14.1 → albert-1.16.0}/docs/collections/roles.md +0 -0
  85. {albert-1.14.1 → albert-1.16.0}/docs/collections/storage_classes.md +0 -0
  86. {albert-1.14.1 → albert-1.16.0}/docs/collections/storage_locations.md +0 -0
  87. {albert-1.14.1 → albert-1.16.0}/docs/collections/substances.md +0 -0
  88. {albert-1.14.1 → albert-1.16.0}/docs/collections/synthesis.md +0 -0
  89. {albert-1.14.1 → albert-1.16.0}/docs/collections/tags.md +0 -0
  90. {albert-1.14.1 → albert-1.16.0}/docs/collections/tasks.md +0 -0
  91. {albert-1.14.1 → albert-1.16.0}/docs/collections/un_numbers.md +0 -0
  92. {albert-1.14.1 → albert-1.16.0}/docs/collections/units.md +0 -0
  93. {albert-1.14.1 → albert-1.16.0}/docs/collections/users.md +0 -0
  94. {albert-1.14.1 → albert-1.16.0}/docs/collections/workflows.md +0 -0
  95. {albert-1.14.1 → albert-1.16.0}/docs/collections/worksheets.md +0 -0
  96. {albert-1.14.1 → albert-1.16.0}/docs/concepts.md +0 -0
  97. {albert-1.14.1 → albert-1.16.0}/docs/configuration.md +0 -0
  98. {albert-1.14.1 → albert-1.16.0}/docs/credentials.md +0 -0
  99. {albert-1.14.1 → albert-1.16.0}/docs/examples/inventory.md +0 -0
  100. {albert-1.14.1 → albert-1.16.0}/docs/examples/notebook.md +0 -0
  101. {albert-1.14.1 → albert-1.16.0}/docs/examples/property_data.md +0 -0
  102. {albert-1.14.1 → albert-1.16.0}/docs/examples/tasks.md +0 -0
  103. {albert-1.14.1 → albert-1.16.0}/docs/index.md +0 -0
  104. {albert-1.14.1 → albert-1.16.0}/docs/installation.md +0 -0
  105. {albert-1.14.1 → albert-1.16.0}/docs/migration.md +0 -0
  106. {albert-1.14.1 → albert-1.16.0}/docs/resources/acls.md +0 -0
  107. {albert-1.14.1 → albert-1.16.0}/docs/resources/activities.md +0 -0
  108. {albert-1.14.1 → albert-1.16.0}/docs/resources/attachments.md +0 -0
  109. {albert-1.14.1 → albert-1.16.0}/docs/resources/batch_data.md +0 -0
  110. {albert-1.14.1 → albert-1.16.0}/docs/resources/btdataset.md +0 -0
  111. {albert-1.14.1 → albert-1.16.0}/docs/resources/btinsight.md +0 -0
  112. {albert-1.14.1 → albert-1.16.0}/docs/resources/btmodel.md +0 -0
  113. {albert-1.14.1 → albert-1.16.0}/docs/resources/cas.md +0 -0
  114. {albert-1.14.1 → albert-1.16.0}/docs/resources/companies.md +0 -0
  115. {albert-1.14.1 → albert-1.16.0}/docs/resources/custom_fields.md +0 -0
  116. {albert-1.14.1 → albert-1.16.0}/docs/resources/custom_templates.md +0 -0
  117. {albert-1.14.1 → albert-1.16.0}/docs/resources/data_columns.md +0 -0
  118. {albert-1.14.1 → albert-1.16.0}/docs/resources/data_templates.md +0 -0
  119. {albert-1.14.1 → albert-1.16.0}/docs/resources/entity_types.md +0 -0
  120. {albert-1.14.1 → albert-1.16.0}/docs/resources/files.md +0 -0
  121. {albert-1.14.1 → albert-1.16.0}/docs/resources/hazards.md +0 -0
  122. {albert-1.14.1 → albert-1.16.0}/docs/resources/identifiers.md +0 -0
  123. {albert-1.14.1 → albert-1.16.0}/docs/resources/inventory.md +0 -0
  124. {albert-1.14.1 → albert-1.16.0}/docs/resources/links.md +0 -0
  125. {albert-1.14.1 → albert-1.16.0}/docs/resources/lists.md +0 -0
  126. {albert-1.14.1 → albert-1.16.0}/docs/resources/locations.md +0 -0
  127. {albert-1.14.1 → albert-1.16.0}/docs/resources/lots.md +0 -0
  128. {albert-1.14.1 → albert-1.16.0}/docs/resources/notebooks.md +0 -0
  129. {albert-1.14.1 → albert-1.16.0}/docs/resources/notes.md +0 -0
  130. {albert-1.14.1 → albert-1.16.0}/docs/resources/parameter_groups.md +0 -0
  131. {albert-1.14.1 → albert-1.16.0}/docs/resources/parameters.md +0 -0
  132. {albert-1.14.1 → albert-1.16.0}/docs/resources/pricings.md +0 -0
  133. {albert-1.14.1 → albert-1.16.0}/docs/resources/product_design.md +0 -0
  134. {albert-1.14.1 → albert-1.16.0}/docs/resources/projects.md +0 -0
  135. {albert-1.14.1 → albert-1.16.0}/docs/resources/property_data.md +0 -0
  136. {albert-1.14.1 → albert-1.16.0}/docs/resources/reports.md +0 -0
  137. {albert-1.14.1 → albert-1.16.0}/docs/resources/roles.md +0 -0
  138. {albert-1.14.1 → albert-1.16.0}/docs/resources/sheets.md +0 -0
  139. {albert-1.14.1 → albert-1.16.0}/docs/resources/storage_classes.md +0 -0
  140. {albert-1.14.1 → albert-1.16.0}/docs/resources/storage_locations.md +0 -0
  141. {albert-1.14.1 → albert-1.16.0}/docs/resources/substances.md +0 -0
  142. {albert-1.14.1 → albert-1.16.0}/docs/resources/synthesis.md +0 -0
  143. {albert-1.14.1 → albert-1.16.0}/docs/resources/tags.md +0 -0
  144. {albert-1.14.1 → albert-1.16.0}/docs/resources/tasks.md +0 -0
  145. {albert-1.14.1 → albert-1.16.0}/docs/resources/un_numbers.md +0 -0
  146. {albert-1.14.1 → albert-1.16.0}/docs/resources/units.md +0 -0
  147. {albert-1.14.1 → albert-1.16.0}/docs/resources/users.md +0 -0
  148. {albert-1.14.1 → albert-1.16.0}/docs/resources/workflows.md +0 -0
  149. {albert-1.14.1 → albert-1.16.0}/docs/resources/worksheets.md +0 -0
  150. {albert-1.14.1 → albert-1.16.0}/docs/sso.md +0 -0
  151. {albert-1.14.1 → albert-1.16.0}/docs/styles/extra.css +0 -0
  152. {albert-1.14.1 → albert-1.16.0}/mkdocs.yml +0 -0
  153. {albert-1.14.1 → albert-1.16.0}/pyproject.toml +0 -0
  154. {albert-1.14.1 → albert-1.16.0}/scripts/validate_release_tag.py +0 -0
  155. {albert-1.14.1 → albert-1.16.0}/scripts/validate_version_bump.py +0 -0
  156. {albert-1.14.1 → albert-1.16.0}/setup.sh +0 -0
  157. {albert-1.14.1 → albert-1.16.0}/src/albert/client.py +0 -0
  158. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/__init__.py +0 -0
  159. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/activities.py +0 -0
  160. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/base.py +0 -0
  161. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/batch_data.py +0 -0
  162. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/btdataset.py +0 -0
  163. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/btmodel.py +0 -0
  164. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/custom_fields.py +0 -0
  165. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/files.py +0 -0
  166. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/hazards.py +0 -0
  167. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/links.py +0 -0
  168. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/notebooks.py +0 -0
  169. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/pricings.py +0 -0
  170. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/product_design.py +0 -0
  171. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/report_templates.py +0 -0
  172. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/reports.py +0 -0
  173. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/roles.py +0 -0
  174. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/storage_classes.py +0 -0
  175. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/substance.py +0 -0
  176. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/synthesis.py +0 -0
  177. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/un_numbers.py +0 -0
  178. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/workflows.py +0 -0
  179. {albert-1.14.1 → albert-1.16.0}/src/albert/collections/worksheets.py +0 -0
  180. {albert-1.14.1 → albert-1.16.0}/src/albert/core/__init__.py +0 -0
  181. {albert-1.14.1 → albert-1.16.0}/src/albert/core/auth/__init__.py +0 -0
  182. {albert-1.14.1 → albert-1.16.0}/src/albert/core/auth/_listener.py +0 -0
  183. {albert-1.14.1 → albert-1.16.0}/src/albert/core/auth/_manager.py +0 -0
  184. {albert-1.14.1 → albert-1.16.0}/src/albert/core/auth/credentials.py +0 -0
  185. {albert-1.14.1 → albert-1.16.0}/src/albert/core/auth/sso.py +0 -0
  186. {albert-1.14.1 → albert-1.16.0}/src/albert/core/base.py +0 -0
  187. {albert-1.14.1 → albert-1.16.0}/src/albert/core/logging.py +0 -0
  188. {albert-1.14.1 → albert-1.16.0}/src/albert/core/pagination.py +0 -0
  189. {albert-1.14.1 → albert-1.16.0}/src/albert/core/session.py +0 -0
  190. {albert-1.14.1 → albert-1.16.0}/src/albert/core/shared/__init__.py +0 -0
  191. {albert-1.14.1 → albert-1.16.0}/src/albert/core/shared/enums.py +0 -0
  192. {albert-1.14.1 → albert-1.16.0}/src/albert/core/shared/identifiers.py +0 -0
  193. {albert-1.14.1 → albert-1.16.0}/src/albert/core/shared/models/base.py +0 -0
  194. {albert-1.14.1 → albert-1.16.0}/src/albert/core/shared/models/patch.py +0 -0
  195. {albert-1.14.1 → albert-1.16.0}/src/albert/core/shared/types.py +0 -0
  196. {albert-1.14.1 → albert-1.16.0}/src/albert/exceptions.py +0 -0
  197. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/__init__.py +0 -0
  198. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/_mixins.py +0 -0
  199. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/acls.py +0 -0
  200. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/activities.py +0 -0
  201. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/attachments.py +0 -0
  202. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/batch_data.py +0 -0
  203. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/btdataset.py +0 -0
  204. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/btinsight.py +0 -0
  205. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/btmodel.py +0 -0
  206. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/cas.py +0 -0
  207. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/companies.py +0 -0
  208. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/custom_fields.py +0 -0
  209. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/data_columns.py +0 -0
  210. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/data_templates.py +0 -0
  211. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/entity_types.py +0 -0
  212. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/facet.py +0 -0
  213. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/files.py +0 -0
  214. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/hazards.py +0 -0
  215. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/inventory.py +0 -0
  216. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/links.py +0 -0
  217. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/lists.py +0 -0
  218. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/locations.py +0 -0
  219. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/lots.py +0 -0
  220. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/notebooks.py +0 -0
  221. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/notes.py +0 -0
  222. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/parameter_groups.py +0 -0
  223. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/parameters.py +0 -0
  224. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/pricings.py +0 -0
  225. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/product_design.py +0 -0
  226. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/property_data.py +0 -0
  227. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/report_templates.py +0 -0
  228. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/reports.py +0 -0
  229. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/roles.py +0 -0
  230. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/sheets.py +0 -0
  231. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/storage_classes.py +0 -0
  232. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/storage_locations.py +0 -0
  233. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/substance.py +0 -0
  234. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/synthesis.py +0 -0
  235. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/tagged_base.py +0 -0
  236. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/tasks.py +0 -0
  237. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/un_numbers.py +0 -0
  238. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/units.py +0 -0
  239. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/users.py +0 -0
  240. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/worker_jobs.py +0 -0
  241. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/workflows.py +0 -0
  242. {albert-1.14.1 → albert-1.16.0}/src/albert/resources/worksheets.py +0 -0
  243. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/__init__.py +0 -0
  244. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/_auth.py +0 -0
  245. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/_patch.py +0 -0
  246. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/data_template.py +0 -0
  247. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/inventory.py +0 -0
  248. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/property_data.py +0 -0
  249. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/tasks.py +0 -0
  250. {albert-1.14.1 → albert-1.16.0}/src/albert/utils/worksheets.py +0 -0
  251. {albert-1.14.1 → albert-1.16.0}/tests/__init__.py +0 -0
  252. {albert-1.14.1 → albert-1.16.0}/tests/collections/__init__.py +0 -0
  253. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_activities.py +0 -0
  254. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_attachments.py +0 -0
  255. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_batch_data.py +0 -0
  256. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_btdataset.py +0 -0
  257. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_btinsight.py +0 -0
  258. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_btmodel.py +0 -0
  259. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_cas.py +0 -0
  260. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_company.py +0 -0
  261. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_custom_fields.py +0 -0
  262. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_data_columns.py +0 -0
  263. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_data_templates.py +0 -0
  264. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_entity_types.py +0 -0
  265. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_files.py +0 -0
  266. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_hazards.py +0 -0
  267. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_links.py +0 -0
  268. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_lists.py +0 -0
  269. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_locations.py +0 -0
  270. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_lots.py +0 -0
  271. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_notebooks.py +0 -0
  272. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_notes.py +0 -0
  273. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_parameter_groups.py +0 -0
  274. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_parameters.py +0 -0
  275. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_pricings.py +0 -0
  276. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_product_design.py +0 -0
  277. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_property_data.py +0 -0
  278. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_report_templates.py +0 -0
  279. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_reports.py +0 -0
  280. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_roles.py +0 -0
  281. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_storage_classes.py +0 -0
  282. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_storage_locations.py +0 -0
  283. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_substance.py +0 -0
  284. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_tags.py +0 -0
  285. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_tasks.py +0 -0
  286. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_un_number.py +0 -0
  287. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_units.py +0 -0
  288. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_users.py +0 -0
  289. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_workflows.py +0 -0
  290. {albert-1.14.1 → albert-1.16.0}/tests/collections/test_worksheet.py +0 -0
  291. {albert-1.14.1 → albert-1.16.0}/tests/core/shared/__init__.py +0 -0
  292. {albert-1.14.1 → albert-1.16.0}/tests/core/shared/test_identifiers.py +0 -0
  293. {albert-1.14.1 → albert-1.16.0}/tests/core/shared/test_types.py +0 -0
  294. {albert-1.14.1 → albert-1.16.0}/tests/core/test_auth.py +0 -0
  295. {albert-1.14.1 → albert-1.16.0}/tests/data/SDS_HCL.pdf +0 -0
  296. {albert-1.14.1 → albert-1.16.0}/tests/data/dontpanic.jpg +0 -0
  297. {albert-1.14.1 → albert-1.16.0}/tests/resources/test_inventory.py +0 -0
  298. {albert-1.14.1 → albert-1.16.0}/tests/resources/test_lots.py +0 -0
  299. {albert-1.14.1 → albert-1.16.0}/tests/resources/test_notebooks.py +0 -0
  300. {albert-1.14.1 → albert-1.16.0}/tests/resources/test_sheets.py +0 -0
  301. {albert-1.14.1 → albert-1.16.0}/tests/seeding.py +0 -0
  302. {albert-1.14.1 → albert-1.16.0}/tests/utils/fake_session.py +0 -0
  303. {albert-1.14.1 → albert-1.16.0}/tests/utils/test_patches.py +0 -0
@@ -0,0 +1,19 @@
1
+ name: release-please-poc
2
+
3
+ on:
4
+ workflow_dispatch: {}
5
+
6
+ permissions:
7
+ contents: write
8
+ pull-requests: write
9
+
10
+ jobs:
11
+ release-please:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: googleapis/release-please-action@v4
15
+ with:
16
+ token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
17
+ release-type: python
18
+ package-name: albert
19
+ target-branch: main
@@ -0,0 +1 @@
1
+ { ".": "1.14.1" }
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.15.0] - 2026-02-04
9
+
10
+ ### Added
11
+
12
+ - Added `CustomTemplatesCollection.create` to support creating custom templates.
13
+ - Added `CustomTemplatesCollection.update_acl` to support updating custom template ACLs.
14
+ - Added `CustomTemplatesCollection.delete` to support deleting custom templates.
15
+
16
+ ### Changed
17
+
18
+ - Standardized list-parameter normalization across collection filters so scalars and
19
+ iterables are handled consistently.
20
+
21
+ ### Fixed
22
+
23
+ - Resolved custom-template ACL handling and schema parsing issues.
24
+ - Defaulted missing custom-template workflow names to a sensible value.
25
+ - Fixed enum parameter resolution to use session-level enum definitions.
26
+
8
27
  ## [1.14.0] - 2025-01-29
9
28
 
10
29
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: albert
3
- Version: 1.14.1
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
@@ -0,0 +1,10 @@
1
+ {
2
+ "release-type": "python",
3
+ "packages": {
4
+ ".": {
5
+ "package-name": "albert",
6
+ "version-file": "src/albert/__init__.py",
7
+ "include-v-in-tag": true
8
+ }
9
+ }
10
+ }
@@ -4,4 +4,4 @@ from albert.core.auth.sso import AlbertSSOClient
4
4
 
5
5
  __all__ = ["Albert", "AlbertClientCredentials", "AlbertSSOClient"]
6
6
 
7
- __version__ = "1.14.1"
7
+ __version__ = "1.16.0"
@@ -9,7 +9,7 @@ from pydantic import validate_call
9
9
  from albert.collections.base import BaseCollection
10
10
  from albert.collections.files import FileCollection
11
11
  from albert.collections.notes import NotesCollection
12
- from albert.core.shared.identifiers import AttachmentId, DataColumnId, InventoryId
12
+ from albert.core.shared.identifiers import AttachmentId, DataColumnId, InventoryId, ProjectId
13
13
  from albert.core.shared.types import MetadataItem
14
14
  from albert.resources.attachments import Attachment, AttachmentCategory
15
15
  from albert.resources.files import FileCategory, FileNamespace
@@ -288,3 +288,47 @@ class AttachmentCollection(BaseCollection):
288
288
 
289
289
  response = self.session.post(self.base_path, json=payload)
290
290
  return Attachment(**response.json())
291
+
292
+ @validate_call
293
+ def upload_and_attach_document_to_project(
294
+ self,
295
+ *,
296
+ project_id: ProjectId,
297
+ file_path: Path,
298
+ ) -> Attachment:
299
+ """Upload a file and attach it as a document to a project.
300
+
301
+ Args:
302
+ project_id: The Albert ID of the project (e.g. "PRO770").
303
+ file_path: Local path to the file to upload.
304
+
305
+ Returns:
306
+ The created Attachment record.
307
+ """
308
+ resolved_path = file_path.expanduser()
309
+ if not resolved_path.is_file():
310
+ raise FileNotFoundError(f"File not found at '{resolved_path}'")
311
+
312
+ content_type = mimetypes.guess_type(resolved_path.name)[0] or "application/octet-stream"
313
+ encoded_file_name = quote(resolved_path.name)
314
+ file_key = f"{project_id}/documents/original/{encoded_file_name}"
315
+
316
+ file_collection = self._get_file_collection()
317
+ with resolved_path.open("rb") as file_handle:
318
+ file_collection.sign_and_upload_file(
319
+ data=file_handle,
320
+ name=file_key,
321
+ namespace=FileNamespace.RESULT,
322
+ content_type=content_type,
323
+ )
324
+
325
+ payload = {
326
+ "parentId": project_id,
327
+ "category": AttachmentCategory.OTHER.value,
328
+ "name": encoded_file_name,
329
+ "key": file_key,
330
+ "nameSpace": FileNamespace.RESULT.value,
331
+ }
332
+
333
+ response = self.session.post(self.base_path, json=payload)
334
+ return Attachment(**response.json())
@@ -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 OrderBy, PaginationMode
9
9
  from albert.core.shared.identifiers import BTInsightId
10
+ from albert.core.utils import ensure_list
10
11
  from albert.resources.btinsight import BTInsight, BTInsightCategory, BTInsightState
11
12
 
12
13
 
@@ -132,17 +133,17 @@ class BTInsightCollection(BaseCollection):
132
133
  """
133
134
  params = {
134
135
  "offset": offset,
135
- "order": OrderBy(order_by).value if order_by else None,
136
+ "order": order_by,
136
137
  "sortBy": sort_by,
137
138
  "text": text,
138
- "name": name,
139
+ "name": ensure_list(name),
139
140
  }
140
- if state:
141
- state = state if isinstance(state, list) else [state]
142
- params["state"] = [BTInsightState(x).value for x in state]
143
- if category:
144
- category = category if isinstance(category, list) else [category]
145
- params["category"] = [BTInsightCategory(x).value for x in category]
141
+
142
+ state_values = ensure_list(state)
143
+ params["state"] = state_values if state_values else None
144
+
145
+ category_values = ensure_list(category)
146
+ params["category"] = category_values if category_values else None
146
147
 
147
148
  return AlbertPaginator(
148
149
  mode=PaginationMode.OFFSET,
@@ -106,7 +106,7 @@ class CasCollection(BaseCollection):
106
106
  An iterator over Cas entities.
107
107
  """
108
108
 
109
- params: dict[str, Any] = {"orderBy": order_by.value}
109
+ params: dict[str, Any] = {"orderBy": order_by}
110
110
  if id is not None:
111
111
  yield self.get_by_id(id=id)
112
112
  return
@@ -7,6 +7,7 @@ from albert.core.logging import logger
7
7
  from albert.core.pagination import AlbertPaginator, PaginationMode
8
8
  from albert.core.session import AlbertSession
9
9
  from albert.core.shared.identifiers import CompanyId
10
+ from albert.core.utils import ensure_list
10
11
  from albert.exceptions import AlbertException
11
12
  from albert.resources.companies import Company
12
13
 
@@ -62,9 +63,8 @@ class CompanyCollection(BaseCollection):
62
63
  "dupDetection": "false",
63
64
  "startKey": start_key,
64
65
  }
65
- if name:
66
- params["name"] = name if isinstance(name, list) else [name]
67
- params["exactMatch"] = str(exact_match).lower()
66
+ params["name"] = ensure_list(name)
67
+ params["exactMatch"] = str(exact_match).lower()
68
68
 
69
69
  return AlbertPaginator(
70
70
  mode=PaginationMode.KEY,
@@ -0,0 +1,414 @@
1
+ from collections.abc import Iterator
2
+
3
+ from pydantic import validate_call
4
+
5
+ from albert.collections.base import BaseCollection
6
+ from albert.collections.tags import TagCollection
7
+ from albert.core.logging import logger
8
+ from albert.core.pagination import AlbertPaginator
9
+ from albert.core.session import AlbertSession
10
+ from albert.core.shared.enums import OrderBy, PaginationMode, Status
11
+ from albert.core.shared.identifiers import CustomTemplateId
12
+ from albert.core.shared.models.patch import PatchOperation
13
+ from albert.core.utils import ensure_list
14
+ from albert.resources.acls import ACL
15
+ from albert.resources.custom_templates import (
16
+ CustomTemplate,
17
+ CustomTemplateSearchItem,
18
+ TemplateCategory,
19
+ )
20
+
21
+
22
+ class CustomTemplatesCollection(BaseCollection):
23
+ """CustomTemplatesCollection is a collection class for managing CustomTemplate entities in the Albert platform."""
24
+
25
+ # _updatable_attributes = {"symbol", "synonyms", "category"}
26
+ _api_version = "v3"
27
+
28
+ def __init__(self, *, session: AlbertSession):
29
+ """
30
+ Initializes the CustomTemplatesCollection with the provided session.
31
+
32
+ Parameters
33
+ ----------
34
+ session : AlbertSession
35
+ The Albert session instance.
36
+ """
37
+ super().__init__(session=session)
38
+ self.base_path = f"/api/{CustomTemplatesCollection._api_version}/customtemplates"
39
+
40
+ @validate_call
41
+ def create(
42
+ self,
43
+ *,
44
+ custom_template: CustomTemplate | list[CustomTemplate],
45
+ ) -> list[CustomTemplate]:
46
+ """
47
+ Creates one or more custom templates.
48
+
49
+ Parameters
50
+ ----------
51
+ custom_template : CustomTemplate | list[CustomTemplate]
52
+ The template entities to create.
53
+
54
+ Returns
55
+ -------
56
+ list[CustomTemplate]
57
+ The created CustomTemplate entities.
58
+ """
59
+ templates = ensure_list(custom_template) or []
60
+ if len(templates) == 0:
61
+ raise ValueError("At least one CustomTemplate must be provided.")
62
+ if len(templates) > 10:
63
+ raise ValueError("A maximum of 10 CustomTemplates can be created at once.")
64
+
65
+ payload = [
66
+ template.model_dump(
67
+ mode="json",
68
+ by_alias=True,
69
+ exclude_none=True,
70
+ exclude_unset=True,
71
+ )
72
+ for template in templates
73
+ ]
74
+ response = self.session.post(url=self.base_path, json=payload)
75
+ response_data = response.json()
76
+ created_payloads = (
77
+ (response_data or {}).get("CreatedItems")
78
+ if response.status_code == 206
79
+ else response_data
80
+ ) or []
81
+
82
+ tag_collection = TagCollection(session=self.session)
83
+
84
+ def resolve_tag(tag_id: str | None) -> dict[str, str] | None:
85
+ if not tag_id:
86
+ return None
87
+ tag = tag_collection.get_by_id(id=tag_id)
88
+ return {"albertId": tag.id or tag_id, "name": tag.tag}
89
+
90
+ def populate_tag_names(section: dict | None) -> None:
91
+ if not isinstance(section, dict):
92
+ return
93
+ tags = section.get("Tags")
94
+ if not tags:
95
+ return
96
+ resolved_tags = []
97
+ for tag in tags:
98
+ if isinstance(tag, dict):
99
+ tag_id = tag.get("id") or tag.get("albertId")
100
+ elif isinstance(tag, str):
101
+ tag_id = tag
102
+ else:
103
+ tag_id = None
104
+
105
+ resolved_tag = resolve_tag(tag_id)
106
+ if resolved_tag:
107
+ resolved_tags.append(resolved_tag)
108
+ section["Tags"] = resolved_tags
109
+
110
+ for payload in created_payloads:
111
+ if not isinstance(payload, dict):
112
+ continue
113
+ populate_tag_names(payload.get("Data"))
114
+
115
+ if response.status_code == 206:
116
+ failed_items = response_data.get("FailedItems") or []
117
+ if failed_items:
118
+ error_messages = []
119
+ for failed in failed_items:
120
+ errors = failed.get("errors") or []
121
+ if errors:
122
+ error_messages.extend(err.get("msg", "Unknown error") for err in errors)
123
+ joined = " | ".join(error_messages) if error_messages else "Unknown error"
124
+ logger.warning(
125
+ "Custom template creation partially succeeded. Errors: %s",
126
+ joined,
127
+ )
128
+
129
+ hydrated_templates = []
130
+ for payload in created_payloads:
131
+ template = CustomTemplate(**payload)
132
+ hydrated = self.get_by_id(id=template.id)
133
+ hydrated_templates.append(hydrated)
134
+
135
+ return hydrated_templates
136
+
137
+ def get_by_id(self, *, id: CustomTemplateId) -> CustomTemplate:
138
+ """Get a Custom Template by ID
139
+
140
+ Parameters
141
+ ----------
142
+ id : str
143
+ id of the custom template
144
+
145
+ Returns
146
+ -------
147
+ CustomTemplate
148
+ The CutomTemplate with the provided ID
149
+ """
150
+ url = f"{self.base_path}/{id}"
151
+ response = self.session.get(url)
152
+ return CustomTemplate(**response.json())
153
+
154
+ def search(
155
+ self,
156
+ *,
157
+ text: str | None = None,
158
+ offset: int | None = 0,
159
+ sort_by: str | None = None,
160
+ order_by: OrderBy | None = None,
161
+ status: Status | None = None,
162
+ created_by: str | None = None,
163
+ category: TemplateCategory | list[TemplateCategory] | None = None,
164
+ created_by_name: str | list[str] | None = None,
165
+ collaborator: str | list[str] | None = None,
166
+ facet_text: str | None = None,
167
+ facet_field: str | None = None,
168
+ contains_field: str | list[str] | None = None,
169
+ contains_text: str | list[str] | None = None,
170
+ my_role: str | list[str] | None = None,
171
+ max_items: int | None = None,
172
+ ) -> Iterator[CustomTemplateSearchItem]:
173
+ """
174
+ Search for CustomTemplate matching the provided criteria.
175
+
176
+ ⚠️ This method returns partial (unhydrated) entities to optimize performance.
177
+ To retrieve fully detailed entities, use :meth:`get_all` instead.
178
+
179
+ Parameters
180
+ ----------
181
+ text : str, optional
182
+ Free text search term.
183
+ offset : int, optional
184
+ Starting offset for pagination.
185
+ sort_by : str, optional
186
+ Field to sort on.
187
+ order_by : OrderBy, optional
188
+ Sort direction for `sort_by`.
189
+ status : Status | str, optional
190
+ Filter results by template status.
191
+ created_by : str, optional
192
+ Filter by creator id.
193
+ category : TemplateCategory | list[TemplateCategory], optional
194
+ Filter by template categories.
195
+ created_by_name : str | list[str], optional
196
+ Filter by creator display name(s).
197
+ collaborator : str | list[str], optional
198
+ Filter by collaborator ids.
199
+ facet_text : str, optional
200
+ Filter text within a facet.
201
+ facet_field : str, optional
202
+ Facet field to search inside.
203
+ contains_field : str | list[str], optional
204
+ Fields to apply contains search to.
205
+ contains_text : str | list[str], optional
206
+ Text values for contains search.
207
+ my_role : str | list[str], optional
208
+ Restrict templates to roles held by the calling user.
209
+ max_items : int, optional
210
+ Maximum number of items to yield client-side.
211
+
212
+ Returns
213
+ -------
214
+ Iterator[CustomTemplateSearchItem]
215
+ An iterator of CustomTemplateSearchItem items.
216
+ """
217
+
218
+ params = {
219
+ "text": text,
220
+ "offset": offset,
221
+ "sortBy": sort_by,
222
+ "order": order_by,
223
+ "status": status,
224
+ "createdBy": created_by,
225
+ "category": ensure_list(category),
226
+ "createdByName": ensure_list(created_by_name),
227
+ "collaborator": ensure_list(collaborator),
228
+ "facetText": facet_text,
229
+ "facetField": facet_field,
230
+ "containsField": ensure_list(contains_field),
231
+ "containsText": ensure_list(contains_text),
232
+ "myRole": ensure_list(my_role),
233
+ }
234
+
235
+ return AlbertPaginator(
236
+ mode=PaginationMode.OFFSET,
237
+ path=f"{self.base_path}/search",
238
+ session=self.session,
239
+ params=params,
240
+ max_items=max_items,
241
+ deserialize=lambda items: [
242
+ CustomTemplateSearchItem.model_validate(x)._bind_collection(self) for x in items
243
+ ],
244
+ )
245
+
246
+ def get_all(
247
+ self,
248
+ *,
249
+ name: str | list[str] | None = None,
250
+ created_by: str | None = None,
251
+ category: TemplateCategory | None = None,
252
+ start_key: str | None = None,
253
+ max_items: int | None = None,
254
+ ) -> Iterator[CustomTemplate]:
255
+ """Iterate over CustomTemplate entities with optional filters.
256
+
257
+ Parameters
258
+ ----------
259
+ name : str | list[str], optional
260
+ Filter by template name(s).
261
+ created_by : str, optional
262
+ Filter by creator id.
263
+ category : TemplateCategory, optional
264
+ Filter by category.
265
+ start_key : str, optional
266
+ Provide the `lastKey` from a previous request to resume pagination.
267
+ max_items : int, optional
268
+ Maximum number of items to return.
269
+
270
+ Returns
271
+ -------
272
+ Iterator[CustomTemplate]
273
+ An iterator of CustomTemplates.
274
+ """
275
+ params = {
276
+ "startKey": start_key,
277
+ "createdBy": created_by,
278
+ "category": category,
279
+ }
280
+ params["name"] = ensure_list(name)
281
+
282
+ return AlbertPaginator(
283
+ mode=PaginationMode.KEY,
284
+ path=self.base_path,
285
+ session=self.session,
286
+ params=params,
287
+ max_items=max_items,
288
+ deserialize=lambda items: [CustomTemplate(**item) for item in items],
289
+ )
290
+
291
+ @validate_call
292
+ def delete(self, *, id: CustomTemplateId) -> None:
293
+ """
294
+ Delete a custom template by id.
295
+
296
+ Parameters
297
+ ----------
298
+ id : CustomTemplateId
299
+ The id of the custom template to delete.
300
+
301
+ Returns
302
+ -------
303
+ None
304
+ """
305
+
306
+ url = f"{self.base_path}/{id}"
307
+ self.session.delete(url)
308
+
309
+ @validate_call
310
+ def update_acl(
311
+ self,
312
+ *,
313
+ custom_template_id: CustomTemplateId,
314
+ acl_class: str | None = None,
315
+ acls: list[ACL] | None = None,
316
+ ) -> CustomTemplate:
317
+ """
318
+ Replace a template's ACL class and/or entries with the provided values.
319
+
320
+ Parameters
321
+ ----------
322
+ custom_template_id : CustomTemplateId
323
+ The id of the custom template to update.
324
+ acl_class : str | None, optional
325
+ The ACL class to set (if provided).
326
+ acls : list[ACL] | None, optional
327
+ The ACL entries to replace on the template.
328
+
329
+ Returns
330
+ -------
331
+ CustomTemplate
332
+ The updated CustomTemplate.
333
+ """
334
+
335
+ if acl_class is None and acls is None:
336
+ raise ValueError("Provide an ACL class and/or ACL entries to update.")
337
+
338
+ data = []
339
+ current_template: CustomTemplate | None = None
340
+
341
+ if acl_class is not None:
342
+ acl_class_value = getattr(acl_class, "value", acl_class)
343
+ data.append(
344
+ {
345
+ "operation": PatchOperation.UPDATE.value,
346
+ "attribute": "class",
347
+ "newValue": acl_class_value,
348
+ }
349
+ )
350
+
351
+ if acls is not None:
352
+ current_template = self.get_by_id(id=custom_template_id)
353
+ current_acl = (
354
+ current_template.acl.fgclist
355
+ if current_template.acl and current_template.acl.fgclist
356
+ else []
357
+ )
358
+ current_entries = {
359
+ entry.id: getattr(entry.fgc, "value", entry.fgc) for entry in current_acl
360
+ }
361
+
362
+ desired_entries = {entry.id: getattr(entry.fgc, "value", entry.fgc) for entry in acls}
363
+
364
+ to_add = []
365
+ to_delete = []
366
+ to_update = []
367
+
368
+ for entry_id, new_fgc in desired_entries.items():
369
+ if entry_id not in current_entries:
370
+ payload = {"id": entry_id}
371
+ if new_fgc is not None:
372
+ payload["fgc"] = new_fgc
373
+ to_add.append(payload)
374
+ else:
375
+ old_fgc = current_entries[entry_id]
376
+ if new_fgc is not None and old_fgc != new_fgc:
377
+ to_update.append(
378
+ {
379
+ "operation": PatchOperation.UPDATE.value,
380
+ "attribute": "fgc",
381
+ "id": entry_id,
382
+ "oldValue": old_fgc,
383
+ "newValue": new_fgc,
384
+ }
385
+ )
386
+
387
+ for entry_id in current_entries:
388
+ if entry_id not in desired_entries:
389
+ to_delete.append({"id": entry_id})
390
+
391
+ if to_add:
392
+ data.append(
393
+ {
394
+ "operation": PatchOperation.ADD.value,
395
+ "attribute": "ACL",
396
+ "newValue": to_add,
397
+ }
398
+ )
399
+ if to_delete:
400
+ data.append(
401
+ {
402
+ "operation": PatchOperation.DELETE.value,
403
+ "attribute": "ACL",
404
+ "oldValue": to_delete,
405
+ }
406
+ )
407
+ data.extend(to_update)
408
+
409
+ if not data:
410
+ return current_template or self.get_by_id(id=custom_template_id)
411
+
412
+ url = f"{self.base_path}/{custom_template_id}/acl"
413
+ self.session.patch(url, json={"data": data})
414
+ return self.get_by_id(id=custom_template_id)
@@ -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 OrderBy, PaginationMode
9
9
  from albert.core.shared.identifiers import DataColumnId
10
+ from albert.core.utils import ensure_list
10
11
  from albert.resources.data_columns import DataColumn
11
12
 
12
13
 
@@ -102,12 +103,12 @@ class DataColumnCollection(BaseCollection):
102
103
  yield from (DataColumn(**item) for item in items)
103
104
 
104
105
  params = {
105
- "orderBy": order_by.value,
106
+ "orderBy": order_by,
106
107
  "startKey": start_key,
107
- "name": [name] if isinstance(name, str) else name,
108
+ "name": ensure_list(name),
108
109
  "exactMatch": exact_match,
109
110
  "default": default,
110
- "dataColumns": [ids] if isinstance(ids, str) else ids,
111
+ "dataColumns": ensure_list(ids),
111
112
  }
112
113
 
113
114
  return AlbertPaginator(
@@ -285,7 +285,7 @@ class DataTemplateCollection(BaseCollection):
285
285
  """
286
286
  params = {
287
287
  "offset": offset,
288
- "order": order_by.value,
288
+ "order": order_by,
289
289
  "text": name,
290
290
  "userId": user_id,
291
291
  }
@@ -282,10 +282,10 @@ class EntityTypeCollection(BaseCollection):
282
282
  Returns an iterator of EntityType items matching the search criteria.
283
283
  """
284
284
  params = {
285
- "service": service.value if service else None,
285
+ "service": service,
286
286
  "limit": max_items,
287
287
  "startKey": start_key,
288
- "orderBy": order.value if order else None,
288
+ "orderBy": order,
289
289
  }
290
290
  return AlbertPaginator(
291
291
  mode=PaginationMode.KEY,