ayon-python-api 1.2.17__py3-none-any.whl → 1.2.19__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.
@@ -9,10 +9,7 @@ from ayon_api.utils import (
9
9
  create_entity_id,
10
10
  NOT_SET,
11
11
  )
12
- from ayon_api.graphql_queries import (
13
- tasks_graphql_query,
14
- tasks_by_folder_paths_graphql_query,
15
- )
12
+ from ayon_api.graphql_queries import tasks_graphql_query
16
13
 
17
14
  from .base import BaseServerAPI
18
15
 
@@ -236,29 +233,21 @@ class TasksAPI(BaseServerAPI):
236
233
  folder path.
237
234
 
238
235
  """
239
- folder_paths = set(folder_paths)
240
- if not project_name or not folder_paths:
241
- return {}
242
-
243
- graphql_filters = {
244
- "projectName": project_name,
245
- "folderPaths": list(folder_paths),
236
+ output = {
237
+ folder_path: []
238
+ for folder_path in folder_paths
239
+ }
240
+ if not project_name or not output:
241
+ return output
242
+
243
+ folder_path_by_id = {
244
+ folder["id"]: folder["path"]
245
+ for folder in self.get_folders(
246
+ project_name,
247
+ folder_paths=output.keys(),
248
+ fields={"id", "path"},
249
+ )
246
250
  }
247
-
248
- if not prepare_list_filters(
249
- graphql_filters,
250
- ("taskNames", task_names),
251
- ("taskTypes", task_types),
252
- ("taskAssigneesAny", assignees),
253
- ("taskAssigneesAll", assignees_all),
254
- ("taskStatuses", statuses),
255
- ("taskTags", tags),
256
- ):
257
- return {}
258
-
259
- filters = self._prepare_advanced_filters(filters)
260
- if filters:
261
- graphql_filters["filter"] = filters
262
251
 
263
252
  if not fields:
264
253
  fields = self.get_default_fields_for_type("task")
@@ -266,31 +255,25 @@ class TasksAPI(BaseServerAPI):
266
255
  fields = set(fields)
267
256
  self._prepare_fields("task", fields, own_attributes)
268
257
 
269
- if active is not None:
270
- fields.add("active")
271
-
272
- self._prepare_link_fields(fields)
273
-
274
- query = tasks_by_folder_paths_graphql_query(fields)
275
- for attr, filter_value in graphql_filters.items():
276
- query.set_variable_value(attr, filter_value)
258
+ fields.add("folderId")
277
259
 
278
- output = {
279
- folder_path: []
280
- for folder_path in folder_paths
281
- }
282
- for parsed_data in query.continuous_query(self):
283
- for folder in parsed_data["project"]["folders"]:
284
- folder_path = folder["path"]
285
- for task in folder["tasks"]:
286
- if active is not None and active is not task["active"]:
287
- continue
288
-
289
- self._convert_entity_data(task)
260
+ for task_entity in self.get_tasks(
261
+ project_name,
262
+ folder_ids=folder_path_by_id.keys(),
263
+ task_names=task_names,
264
+ task_types=task_types,
265
+ assignees=assignees,
266
+ assignees_all=assignees_all,
267
+ statuses=statuses,
268
+ tags=tags,
269
+ active=active,
270
+ filters=filters,
271
+ fields=fields,
272
+ ):
273
+ folder_id = task_entity["folderId"]
274
+ folder_path = folder_path_by_id[folder_id]
275
+ output[folder_path].append(task_entity)
290
276
 
291
- if own_attributes:
292
- fill_own_attribs(task)
293
- output[folder_path].append(task)
294
277
  return output
295
278
 
296
279
  def get_tasks_by_folder_path(
ayon_api/exceptions.py CHANGED
@@ -78,7 +78,11 @@ class HTTPRequestError(RequestError):
78
78
  pass
79
79
 
80
80
 
81
- class GraphQlQueryFailed(Exception):
81
+ class GraphQlQueryError(Exception):
82
+ pass
83
+
84
+
85
+ class GraphQlQueryFailed(GraphQlQueryError):
82
86
  def __init__(self, errors, query, variables):
83
87
  if variables is None:
84
88
  variables = {}
ayon_api/graphql.py CHANGED
@@ -6,7 +6,7 @@ from abc import ABC, abstractmethod
6
6
  import typing
7
7
  from typing import Optional, Iterable, Any, Generator
8
8
 
9
- from .exceptions import GraphQlQueryFailed
9
+ from .exceptions import GraphQlQueryError, GraphQlQueryFailed
10
10
  from .utils import SortOrder
11
11
 
12
12
  if typing.TYPE_CHECKING:
@@ -304,7 +304,7 @@ class GraphQlQuery:
304
304
  str: GraphQl string with variables and headers.
305
305
 
306
306
  Raises:
307
- ValueError: Query has no fiels.
307
+ ValueError: Query has no fields.
308
308
 
309
309
  """
310
310
  if not self._children:
@@ -370,7 +370,7 @@ class GraphQlQuery:
370
370
  variables = self.get_variables_values()
371
371
  response = con.query_graphql(
372
372
  query_str,
373
- self.get_variables_values()
373
+ variables
374
374
  )
375
375
  if response.errors:
376
376
  raise GraphQlQueryFailed(response.errors, query_str, variables)
@@ -396,6 +396,7 @@ class GraphQlQuery:
396
396
  while self.need_query:
397
397
  query_str = self.calculate_query()
398
398
  variables = self.get_variables_values()
399
+
399
400
  response = con.query_graphql(query_str, variables)
400
401
  if response.errors:
401
402
  raise GraphQlQueryFailed(
@@ -902,8 +903,13 @@ class GraphQlQueryEdgeField(BaseGraphQlQueryField):
902
903
  progress_data[cursor_key] = nodes_by_cursor
903
904
 
904
905
  page_info = value["pageInfo"]
905
- new_cursor = page_info["endCursor"]
906
- self._need_query = page_info["hasNextPage"]
906
+ if self._order == SortOrder.ascending:
907
+ new_cursor = page_info["endCursor"]
908
+ self._need_query = page_info["hasNextPage"]
909
+ else:
910
+ new_cursor = page_info["startCursor"]
911
+ self._need_query = page_info["hasPreviousPage"]
912
+
907
913
  edges = value["edges"]
908
914
  # Fake result parse
909
915
  if not edges:
@@ -931,15 +937,18 @@ class GraphQlQueryEdgeField(BaseGraphQlQueryField):
931
937
  for child in self._children:
932
938
  child.parse_result(edge["node"], edge_value, progress_data)
933
939
 
934
- if not self._need_query:
935
- return
936
-
937
940
  change_cursor = True
938
941
  for child in self._children_iter():
939
942
  if child.need_query:
940
943
  change_cursor = False
941
944
 
942
- if change_cursor:
945
+ if change_cursor and self._need_query:
946
+ if new_cursor == self._cursor:
947
+ raise GraphQlQueryError(
948
+ "Cursor didn't change during pagination."
949
+ " This can cause infinite loop."
950
+ )
951
+
943
952
  for child in self._children_iter():
944
953
  child.reset_cursor()
945
954
  self._cursor = new_cursor
@@ -949,9 +958,7 @@ class GraphQlQueryEdgeField(BaseGraphQlQueryField):
949
958
 
950
959
  def get_filters(self) -> dict[str, Any]:
951
960
  filters = super().get_filters()
952
- limit_key = "first"
953
- if self._order == SortOrder.descending:
954
- limit_key = "last"
961
+ limit_key = "first" if self._order == SortOrder.ascending else "last"
955
962
 
956
963
  limit_amount = 300
957
964
  if self._limit:
@@ -959,10 +966,19 @@ class GraphQlQueryEdgeField(BaseGraphQlQueryField):
959
966
  if total > self._limit:
960
967
  limit_amount = self._limit - self._fetched_counter
961
968
 
969
+ if self.child_has_edges:
970
+ # Nested edge fields share a single cursor argument in the query.
971
+ # Query one parent item at a time so child pagination can't be
972
+ # overwritten by another parent from the same outer page.
973
+ limit_amount = 1
974
+
962
975
  filters[limit_key] = limit_amount
963
976
 
964
977
  if self._cursor:
965
- filters["after"] = self._cursor
978
+ cursor_key = (
979
+ "after" if self._order == SortOrder.ascending else "before"
980
+ )
981
+ filters[cursor_key] = self._cursor
966
982
  return filters
967
983
 
968
984
  def calculate_query(self) -> str:
@@ -1000,8 +1016,16 @@ class GraphQlQueryEdgeField(BaseGraphQlQueryField):
1000
1016
  # Add page information
1001
1017
  output.append(edges_offset + "pageInfo {")
1002
1018
  for page_key in (
1003
- "endCursor",
1004
- "hasNextPage",
1019
+ (
1020
+ "endCursor"
1021
+ if self._order == SortOrder.ascending
1022
+ else "startCursor"
1023
+ ),
1024
+ (
1025
+ "hasNextPage"
1026
+ if self._order == SortOrder.ascending
1027
+ else "hasPreviousPage"
1028
+ ),
1005
1029
  ):
1006
1030
  output.append(node_offset + page_key)
1007
1031
  output.append(edges_offset + "}")
@@ -243,56 +243,6 @@ def tasks_graphql_query(fields: set[str]) -> GraphQlQuery:
243
243
  return query
244
244
 
245
245
 
246
- def tasks_by_folder_paths_graphql_query(fields: set[str]) -> GraphQlQuery:
247
- query = GraphQlQuery("TasksByFolderPathQuery")
248
- project_name_var = query.add_variable("projectName", "String!")
249
- task_names_var = query.add_variable("taskNames", "[String!]")
250
- task_types_var = query.add_variable("taskTypes", "[String!]")
251
- folder_paths_var = query.add_variable("folderPaths", "[String!]")
252
- assignees_any_var = query.add_variable("taskAssigneesAny", "[String!]")
253
- assignees_all_var = query.add_variable("taskAssigneesAll", "[String!]")
254
- statuses_var = query.add_variable("taskStatuses", "[String!]")
255
- tags_var = query.add_variable("taskTags", "[String!]")
256
- filter_var = query.add_variable("filter", "String!")
257
-
258
- project_field = query.add_field("project")
259
- project_field.set_filter("name", project_name_var)
260
-
261
- folders_field = project_field.add_field_with_edges("folders")
262
- folders_field.add_field("path")
263
- folders_field.set_filter("paths", folder_paths_var)
264
-
265
- tasks_field = folders_field.add_field_with_edges("tasks")
266
- # WARNING: At the moment when this been created 'names' filter
267
- # is not supported
268
- tasks_field.set_filter("names", task_names_var)
269
- tasks_field.set_filter("taskTypes", task_types_var)
270
- tasks_field.set_filter("assigneesAny", assignees_any_var)
271
- tasks_field.set_filter("assignees", assignees_all_var)
272
- tasks_field.set_filter("statuses", statuses_var)
273
- tasks_field.set_filter("tags", tags_var)
274
- tasks_field.set_filter("filter", filter_var)
275
-
276
- nested_fields = fields_to_dict(fields)
277
-
278
- add_links_fields(tasks_field, nested_fields)
279
-
280
- query_queue = collections.deque()
281
- for key, value in nested_fields.items():
282
- query_queue.append((key, value, tasks_field))
283
-
284
- while query_queue:
285
- item = query_queue.popleft()
286
- key, value, parent = item
287
- field = parent.add_field(key)
288
- if value is FIELD_VALUE:
289
- continue
290
-
291
- for k, v in value.items():
292
- query_queue.append((k, v, field))
293
- return query
294
-
295
-
296
246
  def products_graphql_query(fields: set[str]) -> GraphQlQuery:
297
247
  query = GraphQlQuery("ProductsQuery")
298
248
 
ayon_api/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """Package declaring Python API for AYON server."""
2
- __version__ = "1.2.17"
2
+ __version__ = "1.2.19"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ayon_python_api
3
- Version: 1.2.17
3
+ Version: 1.2.19
4
4
  Summary: AYON Python API
5
5
  Home-page: https://github.com/ynput/ayon-python-api
6
6
  Author: ynput.io
@@ -3,14 +3,14 @@ ayon_api/_api.py,sha256=Ka6a8RNAbMUa_bWodK4nuHBM-3sK6mSKZZKiWgILMHo,254429
3
3
  ayon_api/constants.py,sha256=K8RGj9pdDwhXB2gj8W8djsFdVlvAYAUzILSADVUOVCc,4143
4
4
  ayon_api/entity_hub.py,sha256=-evWrJsGqbuuL8yqGXuxT2ygjzTbodfURgwfc3xIJ-o,119610
5
5
  ayon_api/events.py,sha256=RQ_ct_GTb3KbZ6QWBkYn5m-ZUc6NJDAFFsoy2P_w3dQ,1370
6
- ayon_api/exceptions.py,sha256=3IU0KSyFO4nacdPp5YKh9PIFi7Kw346y1guNDdLDBF0,3637
7
- ayon_api/graphql.py,sha256=PgsdNVAwZymEOoFqUuTtnswv8bjtV0IIfBij2R9WKPU,29749
8
- ayon_api/graphql_queries.py,sha256=8h1AJZA0SMkt5vOYrU1mk5O_W49n2ZobWovN9ciweAI,28499
6
+ ayon_api/exceptions.py,sha256=9inI-TkAGMKuhF84O3FwikW2esgmCdPIeRhbj2ithQU,3692
7
+ ayon_api/graphql.py,sha256=haowWM_TvfotVvz11iD8Wg6ey9TPW-aJTHgSmp2_lm0,30741
8
+ ayon_api/graphql_queries.py,sha256=atupD5oe9t6WCyHy3YSY_0_uR8_c4ysb7d8SxbfZAvk,26455
9
9
  ayon_api/operations.py,sha256=BL9r5V8wXqHx63FhQOUpayceuMd0A5B-vJIb5TcKynQ,55501
10
10
  ayon_api/server_api.py,sha256=RRH4fuHVAtGcKRuosEizWEPfAwXmWWdGkAoSKASYVtc,86233
11
11
  ayon_api/typing.py,sha256=fcdLZAbx_IThJeDQ44TeQLkpoJ6Sj0wpHPtCEFJb4N8,12010
12
12
  ayon_api/utils.py,sha256=OGBjRaCCeQLksZ2XrOL5J2timrulDlNNCni3dx0yi8w,32765
13
- ayon_api/version.py,sha256=vezsPRcgfh6NKVmIYDOqvuXt3Zv4BaXwsgWyopjZmms,75
13
+ ayon_api/version.py,sha256=Kb9pAkFReP_cr8Jeap3qlCcCPJYnMjBvXM_GFpTm3aU,75
14
14
  ayon_api/_api_helpers/__init__.py,sha256=15wxNshWe1htzZhFnwTTflBfQ3tYJzTe6-0hrEUCQbw,1076
15
15
  ayon_api/_api_helpers/actions.py,sha256=OBRAEJSVnhGP0xf8ktQL3M7Ubz64nDmn957qZehaRQ0,10578
16
16
  ayon_api/_api_helpers/activities.py,sha256=Svk3DbXRoIOxdlBpfmerPqNSG4d8M5i4QtxdPNqJ_lM,13831
@@ -27,12 +27,12 @@ ayon_api/_api_helpers/products.py,sha256=fX9Ez_2RGRhDmZU02ucULZzfe8FGZAOFK7Qze1B
27
27
  ayon_api/_api_helpers/projects.py,sha256=ROb7MCzuFg5cRz_Nn7sgHCFnwkocnvJBoe7eQjGSi9c,33830
28
28
  ayon_api/_api_helpers/representations.py,sha256=BU0Oq_JOh6F6zIoiEtTGhRoHdr9WwMXMiaDDs-Oc7Yg,27736
29
29
  ayon_api/_api_helpers/secrets.py,sha256=L74qN38Bp22tDs9CQHWdgw3gsJm7GbnHKU75mCaWuj8,1955
30
- ayon_api/_api_helpers/tasks.py,sha256=1bqGOFbbtM_RSHWIirzj1201MsJfe1WAD2zZkVW9UTg,18770
30
+ ayon_api/_api_helpers/tasks.py,sha256=gW8QbC2V7fNQeirViKyQVugnxfnYkQGGxiv3btYRn30,18135
31
31
  ayon_api/_api_helpers/thumbnails.py,sha256=2mQWU4cSY98J18ImYYt_5CRpm7DyOCO2wCmcLXwtdhk,12281
32
32
  ayon_api/_api_helpers/versions.py,sha256=c9ebZdM9i3J24B4bs2BRRoH937JWvRTWlJ3cFRscdug,22413
33
33
  ayon_api/_api_helpers/workfiles.py,sha256=8ksjCZ5xn7nEAKX792PeIwFNF5flslQwzbcHnJZwcu8,17679
34
- ayon_python_api-1.2.17.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
35
- ayon_python_api-1.2.17.dist-info/METADATA,sha256=sWSxKm6d4JBLDwQpTIL8LHkgoQ_lb6YVndu7v4LWllM,16266
36
- ayon_python_api-1.2.17.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
37
- ayon_python_api-1.2.17.dist-info/top_level.txt,sha256=PKrQbX5Cz53_UmSTR_nIySnBkGyHcBTS88SCw9tuVlc,9
38
- ayon_python_api-1.2.17.dist-info/RECORD,,
34
+ ayon_python_api-1.2.19.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
35
+ ayon_python_api-1.2.19.dist-info/METADATA,sha256=-QmipQecdAPbKkXgWBKFClnIPjPm26HkTnfuwxvRo3U,16266
36
+ ayon_python_api-1.2.19.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
37
+ ayon_python_api-1.2.19.dist-info/top_level.txt,sha256=PKrQbX5Cz53_UmSTR_nIySnBkGyHcBTS88SCw9tuVlc,9
38
+ ayon_python_api-1.2.19.dist-info/RECORD,,