ayon-python-api 1.2.2__tar.gz → 1.2.4__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 (45) hide show
  1. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/PKG-INFO +1 -1
  2. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/__init__.py +18 -2
  3. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api.py +296 -21
  4. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/base.py +16 -0
  5. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/thumbnails.py +70 -0
  6. ayon_python_api-1.2.4/ayon_api/_api_helpers/workfiles.py +521 -0
  7. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/constants.py +4 -0
  8. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/entity_hub.py +8 -3
  9. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/graphql.py +2 -2
  10. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/graphql_queries.py +17 -1
  11. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/operations.py +231 -1
  12. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/typing.py +15 -0
  13. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/version.py +1 -1
  14. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/PKG-INFO +1 -1
  15. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/pyproject.toml +1 -1
  16. ayon_python_api-1.2.2/ayon_api/_api_helpers/workfiles.py +0 -265
  17. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/LICENSE +0 -0
  18. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/README.md +0 -0
  19. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/__init__.py +0 -0
  20. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/actions.py +0 -0
  21. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/activities.py +0 -0
  22. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/attributes.py +0 -0
  23. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/bundles_addons.py +0 -0
  24. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/dependency_packages.py +0 -0
  25. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/events.py +0 -0
  26. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/folders.py +0 -0
  27. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/installers.py +0 -0
  28. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/links.py +0 -0
  29. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/lists.py +0 -0
  30. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/products.py +0 -0
  31. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/projects.py +0 -0
  32. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/representations.py +0 -0
  33. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/secrets.py +0 -0
  34. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/tasks.py +0 -0
  35. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/versions.py +0 -0
  36. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/events.py +0 -0
  37. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/exceptions.py +0 -0
  38. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/server_api.py +0 -0
  39. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_api/utils.py +0 -0
  40. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/SOURCES.txt +0 -0
  41. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/dependency_links.txt +0 -0
  42. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/requires.txt +0 -0
  43. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/top_level.txt +0 -0
  44. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/setup.cfg +0 -0
  45. {ayon_python_api-1.2.2 → ayon_python_api-1.2.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ayon_python_api
3
- Version: 1.2.2
3
+ Version: 1.2.4
4
4
  Summary: AYON Python API
5
5
  Home-page: https://github.com/ynput/ayon-python-api
6
6
  Author: ynput.io
@@ -222,11 +222,17 @@ from ._api import (
222
222
  create_representation,
223
223
  update_representation,
224
224
  delete_representation,
225
+ get_workfile_entities,
226
+ get_workfile_entity,
227
+ get_workfile_entity_by_id,
228
+ create_workfile_entity,
229
+ update_workfile_entity,
230
+ delete_workfile_entity,
225
231
  get_workfiles_info,
226
232
  get_workfile_info,
227
233
  get_workfile_info_by_id,
228
- delete_workfile_info,
229
234
  update_workfile_info,
235
+ delete_workfile_info,
230
236
  get_full_link_type_name,
231
237
  get_link_types,
232
238
  get_link_type,
@@ -265,7 +271,9 @@ from ._api import (
265
271
  get_version_thumbnail,
266
272
  get_workfile_thumbnail,
267
273
  create_thumbnail,
274
+ create_thumbnail_with_stream,
268
275
  update_thumbnail,
276
+ update_thumbnail_from_stream,
269
277
  )
270
278
 
271
279
 
@@ -491,11 +499,17 @@ __all__ = (
491
499
  "create_representation",
492
500
  "update_representation",
493
501
  "delete_representation",
502
+ "get_workfile_entities",
503
+ "get_workfile_entity",
504
+ "get_workfile_entity_by_id",
505
+ "create_workfile_entity",
506
+ "update_workfile_entity",
507
+ "delete_workfile_entity",
494
508
  "get_workfiles_info",
495
509
  "get_workfile_info",
496
510
  "get_workfile_info_by_id",
497
- "delete_workfile_info",
498
511
  "update_workfile_info",
512
+ "delete_workfile_info",
499
513
  "get_full_link_type_name",
500
514
  "get_link_types",
501
515
  "get_link_type",
@@ -534,5 +548,7 @@ __all__ = (
534
548
  "get_version_thumbnail",
535
549
  "get_workfile_thumbnail",
536
550
  "create_thumbnail",
551
+ "create_thumbnail_with_stream",
537
552
  "update_thumbnail",
553
+ "update_thumbnail_from_stream",
538
554
  )
@@ -6157,8 +6157,9 @@ def delete_representation(
6157
6157
  )
6158
6158
 
6159
6159
 
6160
- def get_workfiles_info(
6160
+ def get_workfile_entities(
6161
6161
  project_name: str,
6162
+ *,
6162
6163
  workfile_ids: Optional[Iterable[str]] = None,
6163
6164
  task_ids: Optional[Iterable[str]] = None,
6164
6165
  paths: Optional[Iterable[str]] = None,
@@ -6167,7 +6168,6 @@ def get_workfiles_info(
6167
6168
  tags: Optional[Iterable[str]] = None,
6168
6169
  has_links: Optional[str] = None,
6169
6170
  fields: Optional[Iterable[str]] = None,
6170
- own_attributes=_PLACEHOLDER,
6171
6171
  ) -> Generator[WorkfileInfoDict, None, None]:
6172
6172
  """Workfile info entities by passed filters.
6173
6173
 
@@ -6186,8 +6186,6 @@ def get_workfiles_info(
6186
6186
  fields (Optional[Iterable[str]]): Fields to be queried for
6187
6187
  representation. All possible fields are returned if 'None' is
6188
6188
  passed.
6189
- own_attributes (Optional[bool]): DEPRECATED: Not supported for
6190
- workfiles.
6191
6189
 
6192
6190
  Returns:
6193
6191
  Generator[WorkfileInfoDict, None, None]: Queried workfile info
@@ -6195,7 +6193,7 @@ def get_workfiles_info(
6195
6193
 
6196
6194
  """
6197
6195
  con = get_server_api_connection()
6198
- return con.get_workfiles_info(
6196
+ return con.get_workfile_entities(
6199
6197
  project_name=project_name,
6200
6198
  workfile_ids=workfile_ids,
6201
6199
  task_ids=task_ids,
@@ -6205,16 +6203,15 @@ def get_workfiles_info(
6205
6203
  tags=tags,
6206
6204
  has_links=has_links,
6207
6205
  fields=fields,
6208
- own_attributes=own_attributes,
6209
6206
  )
6210
6207
 
6211
6208
 
6212
- def get_workfile_info(
6209
+ def get_workfile_entity(
6213
6210
  project_name: str,
6214
6211
  task_id: str,
6215
6212
  path: str,
6213
+ *,
6216
6214
  fields: Optional[Iterable[str]] = None,
6217
- own_attributes=_PLACEHOLDER,
6218
6215
  ) -> Optional[WorkfileInfoDict]:
6219
6216
  """Workfile info entity by task id and workfile path.
6220
6217
 
@@ -6225,28 +6222,25 @@ def get_workfile_info(
6225
6222
  fields (Optional[Iterable[str]]): Fields to be queried for
6226
6223
  representation. All possible fields are returned if 'None' is
6227
6224
  passed.
6228
- own_attributes (Optional[bool]): DEPRECATED: Not supported for
6229
- workfiles.
6230
6225
 
6231
6226
  Returns:
6232
6227
  Optional[WorkfileInfoDict]: Workfile info entity or None.
6233
6228
 
6234
6229
  """
6235
6230
  con = get_server_api_connection()
6236
- return con.get_workfile_info(
6231
+ return con.get_workfile_entity(
6237
6232
  project_name=project_name,
6238
6233
  task_id=task_id,
6239
6234
  path=path,
6240
6235
  fields=fields,
6241
- own_attributes=own_attributes,
6242
6236
  )
6243
6237
 
6244
6238
 
6245
- def get_workfile_info_by_id(
6239
+ def get_workfile_entity_by_id(
6246
6240
  project_name: str,
6247
6241
  workfile_id: str,
6242
+ *,
6248
6243
  fields: Optional[Iterable[str]] = None,
6249
- own_attributes=_PLACEHOLDER,
6250
6244
  ) -> Optional[WorkfileInfoDict]:
6251
6245
  """Workfile info entity by id.
6252
6246
 
@@ -6256,23 +6250,119 @@ def get_workfile_info_by_id(
6256
6250
  fields (Optional[Iterable[str]]): Fields to be queried for
6257
6251
  representation. All possible fields are returned if 'None' is
6258
6252
  passed.
6259
- own_attributes (Optional[bool]): DEPRECATED: Not supported for
6260
- workfiles.
6261
6253
 
6262
6254
  Returns:
6263
6255
  Optional[WorkfileInfoDict]: Workfile info entity or None.
6264
6256
 
6265
6257
  """
6266
6258
  con = get_server_api_connection()
6267
- return con.get_workfile_info_by_id(
6259
+ return con.get_workfile_entity_by_id(
6268
6260
  project_name=project_name,
6269
6261
  workfile_id=workfile_id,
6270
6262
  fields=fields,
6271
- own_attributes=own_attributes,
6272
6263
  )
6273
6264
 
6274
6265
 
6275
- def delete_workfile_info(
6266
+ def create_workfile_entity(
6267
+ project_name: str,
6268
+ path: str,
6269
+ task_id: str,
6270
+ *,
6271
+ thumbnail_id: Optional[str] = None,
6272
+ attrib: Optional[dict[str, Any]] = None,
6273
+ data: Optional[dict[str, Any]] = None,
6274
+ tags: Optional[list[str]] = None,
6275
+ status: Optional[str] = None,
6276
+ active: Optional[bool] = None,
6277
+ workfile_id: Optional[str] = None,
6278
+ ) -> str:
6279
+ """Create new workfile.
6280
+
6281
+ Args:
6282
+ project_name (str): Project name.
6283
+ path (str): Representation name.
6284
+ task_id (str): Parent task id.
6285
+ thumbnail_id (Optional[str]): Thumbnail id.
6286
+ attrib (Optional[dict[str, Any]]): Representation attributes.
6287
+ data (Optional[dict[str, Any]]): Representation data.
6288
+ tags (Optional[Iterable[str]]): Representation tags.
6289
+ status (Optional[str]): Representation status.
6290
+ active (Optional[bool]): Representation active state.
6291
+ workfile_id (Optional[str]): Workfile info id. If not
6292
+ passed new id is generated.
6293
+
6294
+ Returns:
6295
+ str: Workfile info id.
6296
+
6297
+ """
6298
+ con = get_server_api_connection()
6299
+ return con.create_workfile_entity(
6300
+ project_name=project_name,
6301
+ path=path,
6302
+ task_id=task_id,
6303
+ thumbnail_id=thumbnail_id,
6304
+ attrib=attrib,
6305
+ data=data,
6306
+ tags=tags,
6307
+ status=status,
6308
+ active=active,
6309
+ workfile_id=workfile_id,
6310
+ )
6311
+
6312
+
6313
+ def update_workfile_entity(
6314
+ project_name: str,
6315
+ workfile_id: str,
6316
+ *,
6317
+ path: Optional[str] = None,
6318
+ task_id: Optional[str] = None,
6319
+ attrib: Optional[dict[str, Any]] = None,
6320
+ data: Optional[dict[str, Any]] = None,
6321
+ tags: Optional[Iterable[str]] = None,
6322
+ status: Optional[str] = None,
6323
+ active: Optional[bool] = None,
6324
+ thumbnail_id: Optional[str] = NOT_SET,
6325
+ created_by: Optional[str] = None,
6326
+ updated_by: Optional[str] = None,
6327
+ ) -> None:
6328
+ """Update workfile entity on server.
6329
+
6330
+ Update of ``attrib`` does change only passed attributes. If you want
6331
+ to unset value, use ``None``.
6332
+
6333
+ Args:
6334
+ project_name (str): Project name.
6335
+ workfile_id (str): Workfile id.
6336
+ path (Optional[str]): New rootless workfile path..
6337
+ task_id (Optional[str]): New parent task id.
6338
+ attrib (Optional[dict[str, Any]]): New attributes.
6339
+ data (Optional[dict[str, Any]]): New data.
6340
+ tags (Optional[Iterable[str]]): New tags.
6341
+ status (Optional[str]): New status.
6342
+ active (Optional[bool]): New active state.
6343
+ thumbnail_id (Optional[str]): New thumbnail id.
6344
+ created_by (Optional[str]): New created by username.
6345
+ updated_by (Optional[str]): New updated by username.
6346
+
6347
+ """
6348
+ con = get_server_api_connection()
6349
+ return con.update_workfile_entity(
6350
+ project_name=project_name,
6351
+ workfile_id=workfile_id,
6352
+ path=path,
6353
+ task_id=task_id,
6354
+ attrib=attrib,
6355
+ data=data,
6356
+ tags=tags,
6357
+ status=status,
6358
+ active=active,
6359
+ thumbnail_id=thumbnail_id,
6360
+ created_by=created_by,
6361
+ updated_by=updated_by,
6362
+ )
6363
+
6364
+
6365
+ def delete_workfile_entity(
6276
6366
  project_name: str,
6277
6367
  workfile_id: str,
6278
6368
  ) -> None:
@@ -6284,12 +6374,127 @@ def delete_workfile_info(
6284
6374
 
6285
6375
  """
6286
6376
  con = get_server_api_connection()
6287
- return con.delete_workfile_info(
6377
+ return con.delete_workfile_entity(
6288
6378
  project_name=project_name,
6289
6379
  workfile_id=workfile_id,
6290
6380
  )
6291
6381
 
6292
6382
 
6383
+ def get_workfiles_info(
6384
+ project_name: str,
6385
+ workfile_ids: Optional[Iterable[str]] = None,
6386
+ task_ids: Optional[Iterable[str]] = None,
6387
+ paths: Optional[Iterable[str]] = None,
6388
+ path_regex: Optional[str] = None,
6389
+ statuses: Optional[Iterable[str]] = None,
6390
+ tags: Optional[Iterable[str]] = None,
6391
+ has_links: Optional[str] = None,
6392
+ fields: Optional[Iterable[str]] = None,
6393
+ own_attributes=_PLACEHOLDER,
6394
+ ) -> Generator[WorkfileInfoDict, None, None]:
6395
+ """DEPRECATED Workfile info entities by passed filters.
6396
+
6397
+ Args:
6398
+ project_name (str): Project under which the entity is located.
6399
+ workfile_ids (Optional[Iterable[str]]): Workfile ids.
6400
+ task_ids (Optional[Iterable[str]]): Task ids.
6401
+ paths (Optional[Iterable[str]]): Rootless workfiles paths.
6402
+ path_regex (Optional[str]): Regex filter for workfile path.
6403
+ statuses (Optional[Iterable[str]]): Workfile info statuses used
6404
+ for filtering.
6405
+ tags (Optional[Iterable[str]]): Workfile info tags used
6406
+ for filtering.
6407
+ has_links (Optional[Literal[IN, OUT, ANY]]): Filter
6408
+ representations with IN/OUT/ANY links.
6409
+ fields (Optional[Iterable[str]]): Fields to be queried for
6410
+ representation. All possible fields are returned if 'None' is
6411
+ passed.
6412
+ own_attributes (Optional[bool]): DEPRECATED: Not supported for
6413
+ workfiles.
6414
+
6415
+ Returns:
6416
+ Generator[WorkfileInfoDict, None, None]: Queried workfile info
6417
+ entites.
6418
+
6419
+ """
6420
+ con = get_server_api_connection()
6421
+ return con.get_workfiles_info(
6422
+ project_name=project_name,
6423
+ workfile_ids=workfile_ids,
6424
+ task_ids=task_ids,
6425
+ paths=paths,
6426
+ path_regex=path_regex,
6427
+ statuses=statuses,
6428
+ tags=tags,
6429
+ has_links=has_links,
6430
+ fields=fields,
6431
+ own_attributes=own_attributes,
6432
+ )
6433
+
6434
+
6435
+ def get_workfile_info(
6436
+ project_name: str,
6437
+ task_id: str,
6438
+ path: str,
6439
+ fields: Optional[Iterable[str]] = None,
6440
+ own_attributes=_PLACEHOLDER,
6441
+ ) -> Optional[WorkfileInfoDict]:
6442
+ """DEPRECATED Workfile info entity by task id and workfile path.
6443
+
6444
+ Args:
6445
+ project_name (str): Project under which the entity is located.
6446
+ task_id (str): Task id.
6447
+ path (str): Rootless workfile path.
6448
+ fields (Optional[Iterable[str]]): Fields to be queried for
6449
+ representation. All possible fields are returned if 'None' is
6450
+ passed.
6451
+ own_attributes (Optional[bool]): DEPRECATED: Not supported for
6452
+ workfiles.
6453
+
6454
+ Returns:
6455
+ Optional[WorkfileInfoDict]: Workfile info entity or None.
6456
+
6457
+ """
6458
+ con = get_server_api_connection()
6459
+ return con.get_workfile_info(
6460
+ project_name=project_name,
6461
+ task_id=task_id,
6462
+ path=path,
6463
+ fields=fields,
6464
+ own_attributes=own_attributes,
6465
+ )
6466
+
6467
+
6468
+ def get_workfile_info_by_id(
6469
+ project_name: str,
6470
+ workfile_id: str,
6471
+ fields: Optional[Iterable[str]] = None,
6472
+ own_attributes=_PLACEHOLDER,
6473
+ ) -> Optional[WorkfileInfoDict]:
6474
+ """DEPRECATED Workfile info entity by id.
6475
+
6476
+ Args:
6477
+ project_name (str): Project under which the entity is located.
6478
+ workfile_id (str): Workfile info id.
6479
+ fields (Optional[Iterable[str]]): Fields to be queried for
6480
+ representation. All possible fields are returned if 'None' is
6481
+ passed.
6482
+ own_attributes (Optional[bool]): DEPRECATED: Not supported for
6483
+ workfiles.
6484
+
6485
+ Returns:
6486
+ Optional[WorkfileInfoDict]: Workfile info entity or None.
6487
+
6488
+ """
6489
+ con = get_server_api_connection()
6490
+ return con.get_workfile_info_by_id(
6491
+ project_name=project_name,
6492
+ workfile_id=workfile_id,
6493
+ fields=fields,
6494
+ own_attributes=own_attributes,
6495
+ )
6496
+
6497
+
6293
6498
  def update_workfile_info(
6294
6499
  project_name: str,
6295
6500
  workfile_id: str,
@@ -6304,7 +6509,7 @@ def update_workfile_info(
6304
6509
  created_by: Optional[str] = None,
6305
6510
  updated_by: Optional[str] = None,
6306
6511
  ) -> None:
6307
- """Update workfile entity on server.
6512
+ """DEPRECATED Update workfile entity on server.
6308
6513
 
6309
6514
  Update of ``attrib`` does change only passed attributes. If you want
6310
6515
  to unset value, use ``None``.
@@ -6341,6 +6546,24 @@ def update_workfile_info(
6341
6546
  )
6342
6547
 
6343
6548
 
6549
+ def delete_workfile_info(
6550
+ project_name: str,
6551
+ workfile_id: str,
6552
+ ) -> None:
6553
+ """DEPRECATED Delete workfile entity on server.
6554
+
6555
+ Args:
6556
+ project_name (str): Project name.
6557
+ workfile_id (str): Workfile id to delete.
6558
+
6559
+ """
6560
+ con = get_server_api_connection()
6561
+ return con.delete_workfile_info(
6562
+ project_name=project_name,
6563
+ workfile_id=workfile_id,
6564
+ )
6565
+
6566
+
6344
6567
  def get_full_link_type_name(
6345
6568
  link_type_name: str,
6346
6569
  input_type: str,
@@ -7503,6 +7726,34 @@ def create_thumbnail(
7503
7726
  )
7504
7727
 
7505
7728
 
7729
+ def create_thumbnail_with_stream(
7730
+ project_name: str,
7731
+ stream: StreamType,
7732
+ thumbnail_id: Optional[str] = None,
7733
+ ) -> str:
7734
+ """Create new thumbnail on server from byte stream.
7735
+
7736
+ Args:
7737
+ project_name (str): Project where the thumbnail will be created
7738
+ and can be used.
7739
+ stream (StreamType): Thumbnail content stream.
7740
+ thumbnail_id (Optional[str]): Prepared if of thumbnail.
7741
+
7742
+ Returns:
7743
+ str: Created thumbnail id.
7744
+
7745
+ Raises:
7746
+ ValueError: When a thumbnail source cannot be processed.
7747
+
7748
+ """
7749
+ con = get_server_api_connection()
7750
+ return con.create_thumbnail_with_stream(
7751
+ project_name=project_name,
7752
+ stream=stream,
7753
+ thumbnail_id=thumbnail_id,
7754
+ )
7755
+
7756
+
7506
7757
  def update_thumbnail(
7507
7758
  project_name: str,
7508
7759
  thumbnail_id: str,
@@ -7528,3 +7779,27 @@ def update_thumbnail(
7528
7779
  thumbnail_id=thumbnail_id,
7529
7780
  src_filepath=src_filepath,
7530
7781
  )
7782
+
7783
+
7784
+ def update_thumbnail_from_stream(
7785
+ project_name: str,
7786
+ thumbnail_id: str,
7787
+ stream: StreamType,
7788
+ ) -> None:
7789
+ """Change thumbnail content by id.
7790
+
7791
+ Update can be also used to create new thumbnail.
7792
+
7793
+ Args:
7794
+ project_name (str): Project where the thumbnail will be created
7795
+ and can be used.
7796
+ thumbnail_id (str): Thumbnail id to update.
7797
+ stream (StreamType): Thumbnail content stream.
7798
+
7799
+ """
7800
+ con = get_server_api_connection()
7801
+ return con.update_thumbnail_from_stream(
7802
+ project_name=project_name,
7803
+ thumbnail_id=thumbnail_id,
7804
+ stream=stream,
7805
+ )
@@ -13,6 +13,7 @@ if typing.TYPE_CHECKING:
13
13
  AnyEntityDict,
14
14
  ServerVersion,
15
15
  ProjectDict,
16
+ StreamType,
16
17
  )
17
18
 
18
19
  _PLACEHOLDER = object()
@@ -84,6 +85,16 @@ class BaseServerAPI:
84
85
  ) -> requests.Response:
85
86
  raise NotImplementedError()
86
87
 
88
+ def upload_file_from_stream(
89
+ self,
90
+ endpoint: str,
91
+ stream: StreamType,
92
+ progress: Optional[TransferProgress] = None,
93
+ request_type: Optional[RequestType] = None,
94
+ **kwargs
95
+ ) -> requests.Response:
96
+ raise NotImplementedError()
97
+
87
98
  def download_file(
88
99
  self,
89
100
  endpoint: str,
@@ -109,6 +120,11 @@ class BaseServerAPI:
109
120
  ) -> Optional[ProjectDict]:
110
121
  raise NotImplementedError()
111
122
 
123
+ def get_user(
124
+ self, username: Optional[str] = None
125
+ ) -> Optional[dict[str, Any]]:
126
+ raise NotImplementedError()
127
+
112
128
  def _prepare_fields(
113
129
  self,
114
130
  entity_type: str,
@@ -2,9 +2,11 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  import warnings
5
+ import typing
5
6
  from typing import Optional
6
7
 
7
8
  from ayon_api.utils import (
9
+ get_media_mime_type_for_stream,
8
10
  get_media_mime_type,
9
11
  ThumbnailContent,
10
12
  RequestTypes,
@@ -13,6 +15,9 @@ from ayon_api.utils import (
13
15
 
14
16
  from .base import BaseServerAPI
15
17
 
18
+ if typing.TYPE_CHECKING:
19
+ from .typing import StreamType
20
+
16
21
 
17
22
  class ThumbnailsAPI(BaseServerAPI):
18
23
  def get_thumbnail_by_id(
@@ -259,6 +264,45 @@ class ThumbnailsAPI(BaseServerAPI):
259
264
  response.raise_for_status()
260
265
  return response.json()["id"]
261
266
 
267
+ def create_thumbnail_with_stream(
268
+ self,
269
+ project_name: str,
270
+ stream: StreamType,
271
+ thumbnail_id: Optional[str] = None,
272
+ ) -> str:
273
+ """Create new thumbnail on server from byte stream.
274
+
275
+ Args:
276
+ project_name (str): Project where the thumbnail will be created
277
+ and can be used.
278
+ stream (StreamType): Thumbnail content stream.
279
+ thumbnail_id (Optional[str]): Prepared if of thumbnail.
280
+
281
+ Returns:
282
+ str: Created thumbnail id.
283
+
284
+ Raises:
285
+ ValueError: When a thumbnail source cannot be processed.
286
+
287
+ """
288
+ if thumbnail_id:
289
+ self.update_thumbnail_from_stream(
290
+ project_name,
291
+ thumbnail_id,
292
+ stream
293
+ )
294
+ return thumbnail_id
295
+
296
+ mime_type = get_media_mime_type_for_stream(stream)
297
+ response = self.upload_file_from_stream(
298
+ f"projects/{project_name}/thumbnails",
299
+ stream,
300
+ request_type=RequestTypes.post,
301
+ headers={"Content-Type": mime_type},
302
+ )
303
+ response.raise_for_status()
304
+ return response.json()["id"]
305
+
262
306
  def update_thumbnail(
263
307
  self, project_name: str, thumbnail_id: str, src_filepath: str
264
308
  ) -> None:
@@ -288,6 +332,32 @@ class ThumbnailsAPI(BaseServerAPI):
288
332
  )
289
333
  response.raise_for_status()
290
334
 
335
+ def update_thumbnail_from_stream(
336
+ self,
337
+ project_name: str,
338
+ thumbnail_id: str,
339
+ stream: StreamType,
340
+ ) -> None:
341
+ """Change thumbnail content by id.
342
+
343
+ Update can be also used to create new thumbnail.
344
+
345
+ Args:
346
+ project_name (str): Project where the thumbnail will be created
347
+ and can be used.
348
+ thumbnail_id (str): Thumbnail id to update.
349
+ stream (StreamType): Thumbnail content stream.
350
+
351
+ """
352
+ mime_type = get_media_mime_type_for_stream(stream)
353
+ response = self.upload_file_from_stream(
354
+ f"projects/{project_name}/thumbnails/{thumbnail_id}",
355
+ stream,
356
+ request_type=RequestTypes.put,
357
+ headers={"Content-Type": mime_type},
358
+ )
359
+ response.raise_for_status()
360
+
291
361
  def _prepare_thumbnail_content(
292
362
  self,
293
363
  project_name: str,