ayon-python-api 1.2.2__py3-none-any.whl → 1.2.4__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.
@@ -5,7 +5,8 @@ import typing
5
5
  from typing import Optional, Iterable, Generator, Any
6
6
 
7
7
  from ayon_api.graphql_queries import workfiles_info_graphql_query
8
- from ayon_api.utils import NOT_SET
8
+ from ayon_api.utils import NOT_SET, create_entity_id
9
+
9
10
  from .base import BaseServerAPI, _PLACEHOLDER
10
11
 
11
12
  if typing.TYPE_CHECKING:
@@ -13,9 +14,10 @@ if typing.TYPE_CHECKING:
13
14
 
14
15
 
15
16
  class WorkfilesAPI(BaseServerAPI):
16
- def get_workfiles_info(
17
+ def get_workfile_entities(
17
18
  self,
18
19
  project_name: str,
20
+ *,
19
21
  workfile_ids: Optional[Iterable[str]] = None,
20
22
  task_ids: Optional[Iterable[str]] =None,
21
23
  paths: Optional[Iterable[str]] =None,
@@ -24,7 +26,6 @@ class WorkfilesAPI(BaseServerAPI):
24
26
  tags: Optional[Iterable[str]] = None,
25
27
  has_links: Optional[str]=None,
26
28
  fields: Optional[Iterable[str]] = None,
27
- own_attributes=_PLACEHOLDER,
28
29
  ) -> Generator[WorkfileInfoDict, None, None]:
29
30
  """Workfile info entities by passed filters.
30
31
 
@@ -43,8 +44,6 @@ class WorkfilesAPI(BaseServerAPI):
43
44
  fields (Optional[Iterable[str]]): Fields to be queried for
44
45
  representation. All possible fields are returned if 'None' is
45
46
  passed.
46
- own_attributes (Optional[bool]): DEPRECATED: Not supported for
47
- workfiles.
48
47
 
49
48
  Returns:
50
49
  Generator[WorkfileInfoDict, None, None]: Queried workfile info
@@ -94,16 +93,6 @@ class WorkfilesAPI(BaseServerAPI):
94
93
  fields = set(fields)
95
94
  self._prepare_fields("workfile", fields)
96
95
 
97
- if own_attributes is not _PLACEHOLDER:
98
- warnings.warn(
99
- (
100
- "'own_attributes' is not supported for workfiles. The"
101
- " argument will be removed form function signature in"
102
- " future (apx. version 1.0.10 or 1.1.0)."
103
- ),
104
- DeprecationWarning
105
- )
106
-
107
96
  query = workfiles_info_graphql_query(fields)
108
97
 
109
98
  for attr, filter_value in filters.items():
@@ -114,13 +103,13 @@ class WorkfilesAPI(BaseServerAPI):
114
103
  self._convert_entity_data(workfile_info)
115
104
  yield workfile_info
116
105
 
117
- def get_workfile_info(
106
+ def get_workfile_entity(
118
107
  self,
119
108
  project_name: str,
120
109
  task_id: str,
121
110
  path: str,
111
+ *,
122
112
  fields: Optional[Iterable[str]] = None,
123
- own_attributes=_PLACEHOLDER,
124
113
  ) -> Optional[WorkfileInfoDict]:
125
114
  """Workfile info entity by task id and workfile path.
126
115
 
@@ -131,8 +120,6 @@ class WorkfilesAPI(BaseServerAPI):
131
120
  fields (Optional[Iterable[str]]): Fields to be queried for
132
121
  representation. All possible fields are returned if 'None' is
133
122
  passed.
134
- own_attributes (Optional[bool]): DEPRECATED: Not supported for
135
- workfiles.
136
123
 
137
124
  Returns:
138
125
  Optional[WorkfileInfoDict]: Workfile info entity or None.
@@ -141,22 +128,21 @@ class WorkfilesAPI(BaseServerAPI):
141
128
  if not task_id or not path:
142
129
  return None
143
130
 
144
- for workfile_info in self.get_workfiles_info(
131
+ for workfile_info in self.get_workfile_entities(
145
132
  project_name,
146
133
  task_ids=[task_id],
147
134
  paths=[path],
148
135
  fields=fields,
149
- own_attributes=own_attributes
150
136
  ):
151
137
  return workfile_info
152
138
  return None
153
139
 
154
- def get_workfile_info_by_id(
140
+ def get_workfile_entity_by_id(
155
141
  self,
156
142
  project_name: str,
157
143
  workfile_id: str,
144
+ *,
158
145
  fields: Optional[Iterable[str]] = None,
159
- own_attributes=_PLACEHOLDER,
160
146
  ) -> Optional[WorkfileInfoDict]:
161
147
  """Workfile info entity by id.
162
148
 
@@ -166,8 +152,6 @@ class WorkfilesAPI(BaseServerAPI):
166
152
  fields (Optional[Iterable[str]]): Fields to be queried for
167
153
  representation. All possible fields are returned if 'None' is
168
154
  passed.
169
- own_attributes (Optional[bool]): DEPRECATED: Not supported for
170
- workfiles.
171
155
 
172
156
  Returns:
173
157
  Optional[WorkfileInfoDict]: Workfile info entity or None.
@@ -176,36 +160,85 @@ class WorkfilesAPI(BaseServerAPI):
176
160
  if not workfile_id:
177
161
  return None
178
162
 
179
- for workfile_info in self.get_workfiles_info(
163
+ for workfile_info in self.get_workfile_entities(
180
164
  project_name,
181
165
  workfile_ids=[workfile_id],
182
166
  fields=fields,
183
- own_attributes=own_attributes
184
167
  ):
185
168
  return workfile_info
186
169
  return None
187
170
 
188
- def delete_workfile_info(
171
+ def create_workfile_entity(
189
172
  self,
190
173
  project_name: str,
191
- workfile_id: str,
192
- ) -> None:
193
- """Delete workfile entity on server.
174
+ path: str,
175
+ task_id: str,
176
+ *,
177
+ thumbnail_id: Optional[str] = None,
178
+ attrib: Optional[dict[str, Any]] = None,
179
+ data: Optional[dict[str, Any]] = None,
180
+ tags: Optional[list[str]] = None,
181
+ status: Optional[str] = None,
182
+ active: Optional[bool] = None,
183
+ workfile_id: Optional[str] = None,
184
+ ) -> str:
185
+ """Create new workfile.
194
186
 
195
187
  Args:
196
188
  project_name (str): Project name.
197
- workfile_id (str): Workfile id to delete.
189
+ path (str): Representation name.
190
+ task_id (str): Parent task id.
191
+ thumbnail_id (Optional[str]): Thumbnail id.
192
+ attrib (Optional[dict[str, Any]]): Representation attributes.
193
+ data (Optional[dict[str, Any]]): Representation data.
194
+ tags (Optional[Iterable[str]]): Representation tags.
195
+ status (Optional[str]): Representation status.
196
+ active (Optional[bool]): Representation active state.
197
+ workfile_id (Optional[str]): Workfile info id. If not
198
+ passed new id is generated.
199
+
200
+ Returns:
201
+ str: Workfile info id.
198
202
 
199
203
  """
200
- response = self.delete(
201
- f"projects/{project_name}/workfiles/{workfile_id}"
204
+ if workfile_id is None:
205
+ workfile_id = create_entity_id()
206
+
207
+ create_data = {
208
+ "id": workfile_id,
209
+ "path": path,
210
+ "taskId": task_id,
211
+ }
212
+ for key, value in (
213
+ ("thumbnailId", thumbnail_id),
214
+ ("attrib", attrib),
215
+ ("data", data),
216
+ ("tags", tags),
217
+ ("status", status),
218
+ ("active", active),
219
+ ):
220
+ if value is not None:
221
+ create_data[key] = value
222
+
223
+ major, minor, patch, _, _ = self.get_server_version_tuple()
224
+ if (major, minor, patch) < (1, 1, 3):
225
+ user = self.get_user()
226
+ username = user["name"]
227
+ create_data["createdBy"] = username
228
+ create_data["updatedBy"] = username
229
+
230
+ response = self.post(
231
+ f"projects/{project_name}/workfiles",
232
+ **create_data
202
233
  )
203
234
  response.raise_for_status()
235
+ return workfile_id
204
236
 
205
- def update_workfile_info(
237
+ def update_workfile_entity(
206
238
  self,
207
239
  project_name: str,
208
240
  workfile_id: str,
241
+ *,
209
242
  path: Optional[str] = None,
210
243
  task_id: Optional[str] = None,
211
244
  attrib: Optional[dict[str, Any]] = None,
@@ -263,3 +296,226 @@ class WorkfilesAPI(BaseServerAPI):
263
296
  **update_data
264
297
  )
265
298
  response.raise_for_status()
299
+
300
+ def delete_workfile_entity(
301
+ self,
302
+ project_name: str,
303
+ workfile_id: str,
304
+ ) -> None:
305
+ """Delete workfile entity on server.
306
+
307
+ Args:
308
+ project_name (str): Project name.
309
+ workfile_id (str): Workfile id to delete.
310
+
311
+ """
312
+ response = self.delete(
313
+ f"projects/{project_name}/workfiles/{workfile_id}"
314
+ )
315
+ response.raise_for_status()
316
+
317
+ # --- DEPRECATED ---
318
+ def get_workfiles_info(
319
+ self,
320
+ project_name: str,
321
+ workfile_ids: Optional[Iterable[str]] = None,
322
+ task_ids: Optional[Iterable[str]] =None,
323
+ paths: Optional[Iterable[str]] =None,
324
+ path_regex: Optional[str] = None,
325
+ statuses: Optional[Iterable[str]] = None,
326
+ tags: Optional[Iterable[str]] = None,
327
+ has_links: Optional[str]=None,
328
+ fields: Optional[Iterable[str]] = None,
329
+ own_attributes=_PLACEHOLDER,
330
+ ) -> Generator[WorkfileInfoDict, None, None]:
331
+ """DEPRECATED Workfile info entities by passed filters.
332
+
333
+ Args:
334
+ project_name (str): Project under which the entity is located.
335
+ workfile_ids (Optional[Iterable[str]]): Workfile ids.
336
+ task_ids (Optional[Iterable[str]]): Task ids.
337
+ paths (Optional[Iterable[str]]): Rootless workfiles paths.
338
+ path_regex (Optional[str]): Regex filter for workfile path.
339
+ statuses (Optional[Iterable[str]]): Workfile info statuses used
340
+ for filtering.
341
+ tags (Optional[Iterable[str]]): Workfile info tags used
342
+ for filtering.
343
+ has_links (Optional[Literal[IN, OUT, ANY]]): Filter
344
+ representations with IN/OUT/ANY links.
345
+ fields (Optional[Iterable[str]]): Fields to be queried for
346
+ representation. All possible fields are returned if 'None' is
347
+ passed.
348
+ own_attributes (Optional[bool]): DEPRECATED: Not supported for
349
+ workfiles.
350
+
351
+ Returns:
352
+ Generator[WorkfileInfoDict, None, None]: Queried workfile info
353
+ entites.
354
+
355
+ """
356
+ if own_attributes is not _PLACEHOLDER:
357
+ warnings.warn(
358
+ (
359
+ "'own_attributes' is not supported for workfiles. The"
360
+ " argument will be removed form function signature in"
361
+ " future (apx. version 1.0.10 or 1.1.0)."
362
+ ),
363
+ DeprecationWarning,
364
+ stacklevel=2,
365
+ )
366
+
367
+ return self.get_workfile_entities(
368
+ project_name,
369
+ workfile_ids=workfile_ids,
370
+ task_ids=task_ids,
371
+ paths=paths,
372
+ path_regex=path_regex,
373
+ statuses=statuses,
374
+ tags=tags,
375
+ has_links=has_links,
376
+ fields=fields,
377
+ )
378
+
379
+ def get_workfile_info(
380
+ self,
381
+ project_name: str,
382
+ task_id: str,
383
+ path: str,
384
+ fields: Optional[Iterable[str]] = None,
385
+ own_attributes=_PLACEHOLDER,
386
+ ) -> Optional[WorkfileInfoDict]:
387
+ """DEPRECATED Workfile info entity by task id and workfile path.
388
+
389
+ Args:
390
+ project_name (str): Project under which the entity is located.
391
+ task_id (str): Task id.
392
+ path (str): Rootless workfile path.
393
+ fields (Optional[Iterable[str]]): Fields to be queried for
394
+ representation. All possible fields are returned if 'None' is
395
+ passed.
396
+ own_attributes (Optional[bool]): DEPRECATED: Not supported for
397
+ workfiles.
398
+
399
+ Returns:
400
+ Optional[WorkfileInfoDict]: Workfile info entity or None.
401
+
402
+ """
403
+ if own_attributes is not _PLACEHOLDER:
404
+ warnings.warn(
405
+ (
406
+ "'own_attributes' is not supported for workfiles. The"
407
+ " argument will be removed form function signature in"
408
+ " future (apx. version 1.0.10 or 1.1.0)."
409
+ ),
410
+ DeprecationWarning,
411
+ stacklevel=2,
412
+ )
413
+
414
+ return self.get_workfile_entity(
415
+ project_name, task_id, path,fields=fields
416
+ )
417
+
418
+ def get_workfile_info_by_id(
419
+ self,
420
+ project_name: str,
421
+ workfile_id: str,
422
+ fields: Optional[Iterable[str]] = None,
423
+ own_attributes=_PLACEHOLDER,
424
+ ) -> Optional[WorkfileInfoDict]:
425
+ """DEPRECATED Workfile info entity by id.
426
+
427
+ Args:
428
+ project_name (str): Project under which the entity is located.
429
+ workfile_id (str): Workfile info id.
430
+ fields (Optional[Iterable[str]]): Fields to be queried for
431
+ representation. All possible fields are returned if 'None' is
432
+ passed.
433
+ own_attributes (Optional[bool]): DEPRECATED: Not supported for
434
+ workfiles.
435
+
436
+ Returns:
437
+ Optional[WorkfileInfoDict]: Workfile info entity or None.
438
+
439
+ """
440
+ if own_attributes is not _PLACEHOLDER:
441
+ warnings.warn(
442
+ (
443
+ "'own_attributes' is not supported for workfiles. The"
444
+ " argument will be removed form function signature in"
445
+ " future (apx. version 1.0.10 or 1.1.0)."
446
+ ),
447
+ DeprecationWarning,
448
+ stacklevel=2,
449
+ )
450
+ return self.get_workfile_entity_by_id(
451
+ project_name,
452
+ workfile_id,
453
+ fields=fields,
454
+ )
455
+
456
+ def update_workfile_info(
457
+ self,
458
+ project_name: str,
459
+ workfile_id: str,
460
+ path: Optional[str] = None,
461
+ task_id: Optional[str] = None,
462
+ attrib: Optional[dict[str, Any]] = None,
463
+ data: Optional[dict[str, Any]] = None,
464
+ tags: Optional[Iterable[str]] = None,
465
+ status: Optional[str] = None,
466
+ active: Optional[bool] = None,
467
+ thumbnail_id: Optional[str] = NOT_SET,
468
+ created_by: Optional[str] = None,
469
+ updated_by: Optional[str] = None,
470
+ ) -> None:
471
+ """DEPRECATED Update workfile entity on server.
472
+
473
+ Update of ``attrib`` does change only passed attributes. If you want
474
+ to unset value, use ``None``.
475
+
476
+ Args:
477
+ project_name (str): Project name.
478
+ workfile_id (str): Workfile id.
479
+ path (Optional[str]): New rootless workfile path..
480
+ task_id (Optional[str]): New parent task id.
481
+ attrib (Optional[dict[str, Any]]): New attributes.
482
+ data (Optional[dict[str, Any]]): New data.
483
+ tags (Optional[Iterable[str]]): New tags.
484
+ status (Optional[str]): New status.
485
+ active (Optional[bool]): New active state.
486
+ thumbnail_id (Optional[str]): New thumbnail id.
487
+ created_by (Optional[str]): New created by username.
488
+ updated_by (Optional[str]): New updated by username.
489
+
490
+ """
491
+ return self.update_workfile_entity(
492
+ project_name,
493
+ workfile_id,
494
+ path=path,
495
+ task_id=task_id,
496
+ attrib=attrib,
497
+ data=data,
498
+ tags=tags,
499
+ status=status,
500
+ active=active,
501
+ thumbnail_id=thumbnail_id,
502
+ created_by=created_by,
503
+ updated_by=updated_by,
504
+ )
505
+
506
+ def delete_workfile_info(
507
+ self,
508
+ project_name: str,
509
+ workfile_id: str,
510
+ ) -> None:
511
+ """DEPRECATED Delete workfile entity on server.
512
+
513
+ Args:
514
+ project_name (str): Project name.
515
+ workfile_id (str): Workfile id to delete.
516
+
517
+ """
518
+ return self.delete_workfile_entity(
519
+ project_name,
520
+ workfile_id,
521
+ )
ayon_api/constants.py CHANGED
@@ -252,4 +252,8 @@ DEFAULT_ENTITY_LIST_FIELDS = {
252
252
  "tags",
253
253
  "updatedAt",
254
254
  "updatedBy",
255
+ "items.id",
256
+ "items.entityId",
257
+ "items.entityType",
258
+ "items.position",
255
259
  }
ayon_api/entity_hub.py CHANGED
@@ -283,14 +283,14 @@ class EntityHub:
283
283
  self.project_name,
284
284
  entity_id,
285
285
  fields=self._get_folder_fields(),
286
- own_attributes=True
286
+ own_attributes=True,
287
287
  )
288
288
  elif entity_type == "task":
289
289
  entity_data = self._connection.get_task_by_id(
290
290
  self.project_name,
291
291
  entity_id,
292
292
  fields=self._get_task_fields(),
293
- own_attributes=True
293
+ own_attributes=True,
294
294
  )
295
295
  elif entity_type == "product":
296
296
  entity_data = self._connection.get_product_by_id(
@@ -781,6 +781,7 @@ class EntityHub:
781
781
  parent_ids=[entity.id],
782
782
  fields=folder_fields,
783
783
  own_attributes=True,
784
+ active=None,
784
785
  ))
785
786
 
786
787
  elif entity.entity_type == "folder":
@@ -789,6 +790,7 @@ class EntityHub:
789
790
  parent_ids=[entity.id],
790
791
  fields=folder_fields,
791
792
  own_attributes=True,
793
+ active=None,
792
794
  ))
793
795
 
794
796
  tasks = list(self._connection.get_tasks(
@@ -796,6 +798,7 @@ class EntityHub:
796
798
  folder_ids=[entity.id],
797
799
  fields=task_fields,
798
800
  own_attributes=True,
801
+ active=None,
799
802
  ))
800
803
 
801
804
  children_ids = {
@@ -897,7 +900,7 @@ class EntityHub:
897
900
  project_name = self.project_name
898
901
  project = self._connection.get_project(
899
902
  project_name,
900
- own_attributes=True
903
+ own_attributes=True,
901
904
  )
902
905
  if not project:
903
906
  raise ValueError(f"Project \"{project_name}\" was not found.")
@@ -949,11 +952,13 @@ class EntityHub:
949
952
  project_entity.name,
950
953
  fields=folder_fields,
951
954
  own_attributes=True,
955
+ active=None,
952
956
  )
953
957
  tasks = self._connection.get_tasks(
954
958
  project_entity.name,
955
959
  fields=task_fields,
956
960
  own_attributes=True,
961
+ active=None,
957
962
  )
958
963
  folders_by_parent_id = collections.defaultdict(list)
959
964
  for folder in folders:
ayon_api/graphql.py CHANGED
@@ -857,8 +857,8 @@ class GraphQlQueryEdgeField(BaseGraphQlQueryField):
857
857
  self._edge_children.append(field)
858
858
  field.set_parent(self)
859
859
 
860
- def add_edge_field(self, name: str) -> GraphQlQueryEdgeField:
861
- item = GraphQlQueryEdgeField(name, self, self._order)
860
+ def add_edge_field(self, name: str) -> GraphQlQueryField:
861
+ item = GraphQlQueryField(name, self, self._order)
862
862
  self.add_obj_edge_field(item)
863
863
  return item
864
864
 
@@ -680,9 +680,25 @@ def entity_lists_graphql_query(fields):
680
680
  entity_lists_field = project_field.add_field_with_edges("entityLists")
681
681
  entity_lists_field.set_filter("ids", entity_list_ids)
682
682
 
683
- nested_fields = fields_to_dict(set(fields))
683
+ fields = set(fields)
684
+ items_field_names = set()
685
+ for field_name in set(fields):
686
+ field_name.removeprefix("items")
687
+ if not field_name.startswith("items"):
688
+ continue
689
+
690
+ fields.discard(field_name)
691
+ field_name = field_name.removeprefix("items").lstrip(".")
692
+ if field_name:
693
+ items_field_names.add(field_name)
684
694
 
685
695
  query_queue = collections.deque()
696
+ if items_field_names:
697
+ items_field = entity_lists_field.add_field_with_edges("items")
698
+ for field_name in items_field_names:
699
+ items_field.add_edge_field(field_name)
700
+
701
+ nested_fields = fields_to_dict(set(fields))
686
702
  for key, value in nested_fields.items():
687
703
  query_queue.append((key, value, entity_lists_field))
688
704