Ayon-Python-Api 1.0.12__tar.gz → 1.1.1__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.
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/PKG-INFO +1 -1
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/__init__.py +2 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/_api.py +37 -4
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/constants.py +1 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/entity_hub.py +8 -70
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/graphql_queries.py +4 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/operations.py +22 -4
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/server_api.py +111 -150
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/utils.py +55 -16
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/version.py +1 -1
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_python_api.egg-info/PKG-INFO +1 -1
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_python_api.egg-info/requires.txt +0 -1
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/pyproject.toml +2 -4
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/LICENSE +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/README.md +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/events.py +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/exceptions.py +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/graphql.py +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_api/typing.py +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_python_api.egg-info/SOURCES.txt +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_python_api.egg-info/dependency_links.txt +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_python_api.egg-info/top_level.txt +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/setup.cfg +0 -0
- {ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/setup.py +0 -0
|
@@ -214,6 +214,7 @@ from ._api import (
|
|
|
214
214
|
get_thumbnail_by_id,
|
|
215
215
|
get_thumbnail,
|
|
216
216
|
get_folder_thumbnail,
|
|
217
|
+
get_task_thumbnail,
|
|
217
218
|
get_version_thumbnail,
|
|
218
219
|
get_workfile_thumbnail,
|
|
219
220
|
create_thumbnail,
|
|
@@ -459,6 +460,7 @@ __all__ = (
|
|
|
459
460
|
"get_thumbnail_by_id",
|
|
460
461
|
"get_thumbnail",
|
|
461
462
|
"get_folder_thumbnail",
|
|
463
|
+
"get_task_thumbnail",
|
|
462
464
|
"get_version_thumbnail",
|
|
463
465
|
"get_workfile_thumbnail",
|
|
464
466
|
"create_thumbnail",
|
|
@@ -706,6 +706,7 @@ def get_server_version_tuple() -> Tuple[int, int, int, str, str]:
|
|
|
706
706
|
def get_users(
|
|
707
707
|
project_name: Optional[str] = None,
|
|
708
708
|
usernames: Optional[Iterable[str]] = None,
|
|
709
|
+
emails: Optional[Iterable[str]] = None,
|
|
709
710
|
fields: Optional[Iterable[str]] = None,
|
|
710
711
|
) -> Generator[Dict[str, Any], None, None]:
|
|
711
712
|
"""Get Users.
|
|
@@ -716,6 +717,7 @@ def get_users(
|
|
|
716
717
|
Args:
|
|
717
718
|
project_name (Optional[str]): Project name.
|
|
718
719
|
usernames (Optional[Iterable[str]]): Filter by usernames.
|
|
720
|
+
emails (Optional[Iterable[str]]): Filter by emails.
|
|
719
721
|
fields (Optional[Iterable[str]]): Fields to be queried
|
|
720
722
|
for users.
|
|
721
723
|
|
|
@@ -727,6 +729,7 @@ def get_users(
|
|
|
727
729
|
return con.get_users(
|
|
728
730
|
project_name=project_name,
|
|
729
731
|
usernames=usernames,
|
|
732
|
+
emails=emails,
|
|
730
733
|
fields=fields,
|
|
731
734
|
)
|
|
732
735
|
|
|
@@ -5472,6 +5475,7 @@ def create_representation(
|
|
|
5472
5475
|
files: Optional[List[Dict[str, Any]]] = None,
|
|
5473
5476
|
attrib: Optional[Dict[str, Any]] = None,
|
|
5474
5477
|
data: Optional[Dict[str, Any]] = None,
|
|
5478
|
+
traits: Optional[Dict[str, Any]] = None,
|
|
5475
5479
|
tags: Optional[List[str]] = None,
|
|
5476
5480
|
status: Optional[str] = None,
|
|
5477
5481
|
active: Optional[bool] = None,
|
|
@@ -5486,6 +5490,8 @@ def create_representation(
|
|
|
5486
5490
|
files (Optional[list[dict]]): Representation files information.
|
|
5487
5491
|
attrib (Optional[dict[str, Any]]): Representation attributes.
|
|
5488
5492
|
data (Optional[dict[str, Any]]): Representation data.
|
|
5493
|
+
traits (Optional[dict[str, Any]]): Representation traits
|
|
5494
|
+
serialized data as dict.
|
|
5489
5495
|
tags (Optional[Iterable[str]]): Representation tags.
|
|
5490
5496
|
status (Optional[str]): Representation status.
|
|
5491
5497
|
active (Optional[bool]): Representation active state.
|
|
@@ -5504,6 +5510,7 @@ def create_representation(
|
|
|
5504
5510
|
files=files,
|
|
5505
5511
|
attrib=attrib,
|
|
5506
5512
|
data=data,
|
|
5513
|
+
traits=traits,
|
|
5507
5514
|
tags=tags,
|
|
5508
5515
|
status=status,
|
|
5509
5516
|
active=active,
|
|
@@ -5519,6 +5526,7 @@ def update_representation(
|
|
|
5519
5526
|
files: Optional[List[Dict[str, Any]]] = None,
|
|
5520
5527
|
attrib: Optional[Dict[str, Any]] = None,
|
|
5521
5528
|
data: Optional[Dict[str, Any]] = None,
|
|
5529
|
+
traits: Optional[Dict[str, Any]] = None,
|
|
5522
5530
|
tags: Optional[List[str]] = None,
|
|
5523
5531
|
status: Optional[str] = None,
|
|
5524
5532
|
active: Optional[bool] = None,
|
|
@@ -5539,6 +5547,7 @@ def update_representation(
|
|
|
5539
5547
|
information.
|
|
5540
5548
|
attrib (Optional[dict[str, Any]]): New attributes.
|
|
5541
5549
|
data (Optional[dict[str, Any]]): New data.
|
|
5550
|
+
traits (Optional[dict[str, Any]]): New traits.
|
|
5542
5551
|
tags (Optional[Iterable[str]]): New tags.
|
|
5543
5552
|
status (Optional[str]): New status.
|
|
5544
5553
|
active (Optional[bool]): New active state.
|
|
@@ -5553,6 +5562,7 @@ def update_representation(
|
|
|
5553
5562
|
files=files,
|
|
5554
5563
|
attrib=attrib,
|
|
5555
5564
|
data=data,
|
|
5565
|
+
traits=traits,
|
|
5556
5566
|
tags=tags,
|
|
5557
5567
|
status=status,
|
|
5558
5568
|
active=active,
|
|
@@ -5698,9 +5708,10 @@ def get_thumbnail_by_id(
|
|
|
5698
5708
|
) -> ThumbnailContent:
|
|
5699
5709
|
"""Get thumbnail from server by id.
|
|
5700
5710
|
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5711
|
+
Warnings:
|
|
5712
|
+
Please keep in mind that used endpoint is allowed only for admins
|
|
5713
|
+
and managers. Use 'get_thumbnail' with entity type and id
|
|
5714
|
+
to allow access for artists.
|
|
5704
5715
|
|
|
5705
5716
|
Notes:
|
|
5706
5717
|
It is recommended to use one of prepared entity type specific
|
|
@@ -5736,7 +5747,7 @@ def get_thumbnail(
|
|
|
5736
5747
|
"""Get thumbnail from server.
|
|
5737
5748
|
|
|
5738
5749
|
Permissions of thumbnails are related to entities so thumbnails must
|
|
5739
|
-
be queried per entity. So an entity type and entity
|
|
5750
|
+
be queried per entity. So an entity type and entity id is required
|
|
5740
5751
|
to be passed.
|
|
5741
5752
|
|
|
5742
5753
|
Notes:
|
|
@@ -5794,6 +5805,28 @@ def get_folder_thumbnail(
|
|
|
5794
5805
|
)
|
|
5795
5806
|
|
|
5796
5807
|
|
|
5808
|
+
def get_task_thumbnail(
|
|
5809
|
+
project_name: str,
|
|
5810
|
+
task_id: str,
|
|
5811
|
+
) -> ThumbnailContent:
|
|
5812
|
+
"""Prepared method to receive thumbnail for task entity.
|
|
5813
|
+
|
|
5814
|
+
Args:
|
|
5815
|
+
project_name (str): Project under which the entity is located.
|
|
5816
|
+
task_id (str): Folder id for which thumbnail should be returned.
|
|
5817
|
+
|
|
5818
|
+
Returns:
|
|
5819
|
+
ThumbnailContent: Thumbnail content wrapper. Does not have to be
|
|
5820
|
+
valid.
|
|
5821
|
+
|
|
5822
|
+
"""
|
|
5823
|
+
con = get_server_api_connection()
|
|
5824
|
+
return con.get_task_thumbnail(
|
|
5825
|
+
project_name=project_name,
|
|
5826
|
+
task_id=task_id,
|
|
5827
|
+
)
|
|
5828
|
+
|
|
5829
|
+
|
|
5797
5830
|
def get_version_thumbnail(
|
|
5798
5831
|
project_name: str,
|
|
5799
5832
|
version_id: str,
|
|
@@ -49,66 +49,22 @@ class EntityHub(object):
|
|
|
49
49
|
Args:
|
|
50
50
|
project_name (str): Name of project where changes will happen.
|
|
51
51
|
connection (ServerAPI): Connection to server with logged user.
|
|
52
|
-
allow_data_changes (bool): This option gives ability to change 'data'
|
|
53
|
-
key on entities. This is not recommended as 'data' may be used for
|
|
54
|
-
secure information and would also slow down server queries. Content
|
|
55
|
-
of 'data' key can't be received only GraphQl.
|
|
56
52
|
|
|
57
53
|
"""
|
|
58
54
|
|
|
59
|
-
def __init__(
|
|
60
|
-
self, project_name, connection=None, allow_data_changes=None
|
|
61
|
-
):
|
|
55
|
+
def __init__(self, project_name, connection=None):
|
|
62
56
|
if not connection:
|
|
63
57
|
connection = get_server_api_connection()
|
|
64
|
-
major, minor, _, _, _ = connection.server_version_tuple
|
|
65
|
-
path_start_with_slash = True
|
|
66
|
-
if (major, minor) < (0, 6):
|
|
67
|
-
path_start_with_slash = False
|
|
68
|
-
|
|
69
|
-
if allow_data_changes is None:
|
|
70
|
-
allow_data_changes = connection.graphql_allows_data_in_query
|
|
71
58
|
|
|
72
59
|
self._connection = connection
|
|
73
|
-
self._path_start_with_slash = path_start_with_slash
|
|
74
60
|
|
|
75
61
|
self._project_name = project_name
|
|
76
62
|
self._entities_by_id = {}
|
|
77
63
|
self._entities_by_parent_id = collections.defaultdict(list)
|
|
78
64
|
self._project_entity = UNKNOWN_VALUE
|
|
79
65
|
|
|
80
|
-
self._allow_data_changes = allow_data_changes
|
|
81
|
-
|
|
82
66
|
self._path_reset_queue = None
|
|
83
67
|
|
|
84
|
-
@property
|
|
85
|
-
def allow_data_changes(self):
|
|
86
|
-
"""Entity hub allows changes of 'data' key on entities.
|
|
87
|
-
|
|
88
|
-
Data are private and not all users may have access to them.
|
|
89
|
-
|
|
90
|
-
Older version of AYON server allowed to get 'data' for entity only
|
|
91
|
-
using REST api calls, which means to query each entity on-by-one
|
|
92
|
-
from server.
|
|
93
|
-
|
|
94
|
-
Returns:
|
|
95
|
-
bool: Data changes are allowed.
|
|
96
|
-
|
|
97
|
-
"""
|
|
98
|
-
return self._allow_data_changes
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def path_start_with_slash(self):
|
|
102
|
-
"""Folder path should start with slash.
|
|
103
|
-
|
|
104
|
-
This changed in 0.6.x server version.
|
|
105
|
-
|
|
106
|
-
Returns:
|
|
107
|
-
bool: Path starts with slash.
|
|
108
|
-
|
|
109
|
-
"""
|
|
110
|
-
return self._path_start_with_slash
|
|
111
|
-
|
|
112
68
|
@property
|
|
113
69
|
def project_name(self):
|
|
114
70
|
"""Project name which is maintained by hub.
|
|
@@ -898,8 +854,7 @@ class EntityHub(object):
|
|
|
898
854
|
self._connection.get_default_fields_for_type("folder")
|
|
899
855
|
)
|
|
900
856
|
folder_fields.add("hasProducts")
|
|
901
|
-
|
|
902
|
-
folder_fields.add("data")
|
|
857
|
+
folder_fields.add("data")
|
|
903
858
|
return folder_fields
|
|
904
859
|
|
|
905
860
|
def _get_task_fields(self) -> Set[str]:
|
|
@@ -1717,10 +1672,7 @@ class BaseEntity(ABC):
|
|
|
1717
1672
|
|
|
1718
1673
|
"""
|
|
1719
1674
|
changes = {}
|
|
1720
|
-
if
|
|
1721
|
-
self._entity_hub.allow_data_changes
|
|
1722
|
-
and self._data is not UNKNOWN_VALUE
|
|
1723
|
-
):
|
|
1675
|
+
if self._data is not UNKNOWN_VALUE:
|
|
1724
1676
|
data_changes = self._data.get_changes()
|
|
1725
1677
|
if data_changes:
|
|
1726
1678
|
changes["data"] = data_changes
|
|
@@ -3149,10 +3101,8 @@ class FolderEntity(BaseEntity):
|
|
|
3149
3101
|
if parent.entity_type == "folder":
|
|
3150
3102
|
parent_path = parent.path
|
|
3151
3103
|
path = "/".join([parent_path, self.name])
|
|
3152
|
-
elif self._entity_hub.path_start_with_slash:
|
|
3153
|
-
path = "/{}".format(self.name)
|
|
3154
3104
|
else:
|
|
3155
|
-
path = self.name
|
|
3105
|
+
path = "/{}".format(self.name)
|
|
3156
3106
|
self._path = path
|
|
3157
3107
|
return self._path
|
|
3158
3108
|
|
|
@@ -3260,10 +3210,7 @@ class FolderEntity(BaseEntity):
|
|
|
3260
3210
|
if self.thumbnail_id is not UNKNOWN_VALUE:
|
|
3261
3211
|
output["thumbnailId"] = self.thumbnail_id
|
|
3262
3212
|
|
|
3263
|
-
if
|
|
3264
|
-
self._entity_hub.allow_data_changes
|
|
3265
|
-
and self._data is not UNKNOWN_VALUE
|
|
3266
|
-
):
|
|
3213
|
+
if self._data is not UNKNOWN_VALUE:
|
|
3267
3214
|
output["data"] = self._data.get_new_entity_value()
|
|
3268
3215
|
return output
|
|
3269
3216
|
|
|
@@ -3451,10 +3398,7 @@ class TaskEntity(BaseEntity):
|
|
|
3451
3398
|
if self.assignees:
|
|
3452
3399
|
output["assignees"] = self.assignees
|
|
3453
3400
|
|
|
3454
|
-
if
|
|
3455
|
-
self._entity_hub.allow_data_changes
|
|
3456
|
-
and self._data is not UNKNOWN_VALUE
|
|
3457
|
-
):
|
|
3401
|
+
if self._data is not UNKNOWN_VALUE:
|
|
3458
3402
|
output["data"] = self._data.get_new_entity_value()
|
|
3459
3403
|
return output
|
|
3460
3404
|
|
|
@@ -3561,10 +3505,7 @@ class ProductEntity(BaseEntity):
|
|
|
3561
3505
|
if self.tags:
|
|
3562
3506
|
output["tags"] = self.tags
|
|
3563
3507
|
|
|
3564
|
-
if
|
|
3565
|
-
self._entity_hub.allow_data_changes
|
|
3566
|
-
and self._data is not UNKNOWN_VALUE
|
|
3567
|
-
):
|
|
3508
|
+
if self._data is not UNKNOWN_VALUE:
|
|
3568
3509
|
output["data"] = self._data.get_new_entity_value()
|
|
3569
3510
|
return output
|
|
3570
3511
|
|
|
@@ -3693,9 +3634,6 @@ class VersionEntity(BaseEntity):
|
|
|
3693
3634
|
if self.status:
|
|
3694
3635
|
output["status"] = self.status
|
|
3695
3636
|
|
|
3696
|
-
if
|
|
3697
|
-
self._entity_hub.allow_data_changes
|
|
3698
|
-
and self._data is not UNKNOWN_VALUE
|
|
3699
|
-
):
|
|
3637
|
+
if self._data is not UNKNOWN_VALUE:
|
|
3700
3638
|
output["data"] = self._data.get_new_entity_value()
|
|
3701
3639
|
return output
|
|
@@ -341,6 +341,7 @@ def versions_graphql_query(fields):
|
|
|
341
341
|
project_name_var = query.add_variable("projectName", "String!")
|
|
342
342
|
product_ids_var = query.add_variable("productIds", "[String!]")
|
|
343
343
|
version_ids_var = query.add_variable("versionIds", "[String!]")
|
|
344
|
+
task_ids_var = query.add_variable("taskIds", "[String!]")
|
|
344
345
|
versions_var = query.add_variable("versions", "[Int!]")
|
|
345
346
|
hero_only_var = query.add_variable("heroOnly", "Boolean")
|
|
346
347
|
latest_only_var = query.add_variable("latestOnly", "Boolean")
|
|
@@ -357,6 +358,7 @@ def versions_graphql_query(fields):
|
|
|
357
358
|
versions_field.set_filter("ids", version_ids_var)
|
|
358
359
|
versions_field.set_filter("productIds", product_ids_var)
|
|
359
360
|
versions_field.set_filter("versions", versions_var)
|
|
361
|
+
versions_field.set_filter("taskIds", task_ids_var)
|
|
360
362
|
versions_field.set_filter("heroOnly", hero_only_var)
|
|
361
363
|
versions_field.set_filter("latestOnly", latest_only_var)
|
|
362
364
|
versions_field.set_filter("heroOrLatestOnly", hero_or_latest_only_var)
|
|
@@ -617,10 +619,12 @@ def events_graphql_query(fields, order, use_states=False):
|
|
|
617
619
|
def users_graphql_query(fields):
|
|
618
620
|
query = GraphQlQuery("Users")
|
|
619
621
|
names_var = query.add_variable("userNames", "[String!]")
|
|
622
|
+
emails_var = query.add_variable("emails", "[String!]")
|
|
620
623
|
project_name_var = query.add_variable("projectName", "String!")
|
|
621
624
|
|
|
622
625
|
users_field = query.add_field_with_edges("users")
|
|
623
626
|
users_field.set_filter("names", names_var)
|
|
627
|
+
users_field.set_filter("emails", emails_var)
|
|
624
628
|
users_field.set_filter("projectName", project_name_var)
|
|
625
629
|
|
|
626
630
|
nested_fields = fields_to_dict(set(fields))
|
|
@@ -276,7 +276,8 @@ def new_representation_entity(
|
|
|
276
276
|
tags=None,
|
|
277
277
|
attribs=None,
|
|
278
278
|
data=None,
|
|
279
|
-
|
|
279
|
+
traits=None,
|
|
280
|
+
entity_id=None,
|
|
280
281
|
):
|
|
281
282
|
"""Create skeleton data of representation entity.
|
|
282
283
|
|
|
@@ -290,6 +291,8 @@ def new_representation_entity(
|
|
|
290
291
|
attribs (Optional[Dict[str, Any]]): Explicitly set attributes
|
|
291
292
|
of representation.
|
|
292
293
|
data (Optional[Dict[str, Any]]): Representation entity data.
|
|
294
|
+
traits (Optional[Dict[str, Any]]): Representation traits. Empty
|
|
295
|
+
if not passed.
|
|
293
296
|
entity_id (Optional[str]): Predefined id of entity. New id is created
|
|
294
297
|
if not passed.
|
|
295
298
|
|
|
@@ -309,8 +312,10 @@ def new_representation_entity(
|
|
|
309
312
|
"files": files,
|
|
310
313
|
"name": name,
|
|
311
314
|
"data": data,
|
|
312
|
-
"attrib": attribs
|
|
315
|
+
"attrib": attribs,
|
|
313
316
|
}
|
|
317
|
+
if traits:
|
|
318
|
+
output["traits"] = traits
|
|
314
319
|
if tags:
|
|
315
320
|
output["tags"] = tags
|
|
316
321
|
if status:
|
|
@@ -1188,7 +1193,10 @@ class OperationsSession(object):
|
|
|
1188
1193
|
update_data[key] = value
|
|
1189
1194
|
|
|
1190
1195
|
return self.update_entity(
|
|
1191
|
-
project_name,
|
|
1196
|
+
project_name,
|
|
1197
|
+
"product",
|
|
1198
|
+
product_id,
|
|
1199
|
+
update_data
|
|
1192
1200
|
)
|
|
1193
1201
|
|
|
1194
1202
|
def delete_product(self, project_name, product_id):
|
|
@@ -1356,6 +1364,7 @@ class OperationsSession(object):
|
|
|
1356
1364
|
files=None,
|
|
1357
1365
|
attrib=None,
|
|
1358
1366
|
data=None,
|
|
1367
|
+
traits=None,
|
|
1359
1368
|
tags=None,
|
|
1360
1369
|
status=None,
|
|
1361
1370
|
active=None,
|
|
@@ -1370,6 +1379,8 @@ class OperationsSession(object):
|
|
|
1370
1379
|
files (Optional[list[dict]]): Representation files information.
|
|
1371
1380
|
attrib (Optional[dict[str, Any]]): Representation attributes.
|
|
1372
1381
|
data (Optional[dict[str, Any]]): Representation data.
|
|
1382
|
+
traits (Optional[Dict[str, Any]]): Representation traits. Empty
|
|
1383
|
+
if not passed.
|
|
1373
1384
|
tags (Optional[Iterable[str]]): Representation tags.
|
|
1374
1385
|
status (Optional[str]): Representation status.
|
|
1375
1386
|
active (Optional[bool]): Representation active state.
|
|
@@ -1391,6 +1402,7 @@ class OperationsSession(object):
|
|
|
1391
1402
|
("files", files),
|
|
1392
1403
|
("attrib", attrib),
|
|
1393
1404
|
("data", data),
|
|
1405
|
+
("traits", traits),
|
|
1394
1406
|
("tags", tags),
|
|
1395
1407
|
("status", status),
|
|
1396
1408
|
("active", active),
|
|
@@ -1413,6 +1425,7 @@ class OperationsSession(object):
|
|
|
1413
1425
|
files=None,
|
|
1414
1426
|
attrib=None,
|
|
1415
1427
|
data=None,
|
|
1428
|
+
traits=None,
|
|
1416
1429
|
tags=None,
|
|
1417
1430
|
status=None,
|
|
1418
1431
|
active=None,
|
|
@@ -1433,6 +1446,7 @@ class OperationsSession(object):
|
|
|
1433
1446
|
information.
|
|
1434
1447
|
attrib (Optional[dict[str, Any]]): New attributes.
|
|
1435
1448
|
data (Optional[dict[str, Any]]): New data.
|
|
1449
|
+
traits (Optional[Dict[str, Any]]): New representation traits.
|
|
1436
1450
|
tags (Optional[Iterable[str]]): New tags.
|
|
1437
1451
|
status (Optional[str]): New status.
|
|
1438
1452
|
active (Optional[bool]): New active state.
|
|
@@ -1448,6 +1462,7 @@ class OperationsSession(object):
|
|
|
1448
1462
|
("files", files),
|
|
1449
1463
|
("attrib", attrib),
|
|
1450
1464
|
("data", data),
|
|
1465
|
+
("traits", traits),
|
|
1451
1466
|
("tags", tags),
|
|
1452
1467
|
("status", status),
|
|
1453
1468
|
("active", active),
|
|
@@ -1456,7 +1471,10 @@ class OperationsSession(object):
|
|
|
1456
1471
|
update_data[key] = value
|
|
1457
1472
|
|
|
1458
1473
|
return self.update_entity(
|
|
1459
|
-
project_name,
|
|
1474
|
+
project_name,
|
|
1475
|
+
"representation",
|
|
1476
|
+
representation_id,
|
|
1477
|
+
update_data
|
|
1460
1478
|
)
|
|
1461
1479
|
|
|
1462
1480
|
def delete_representation(self, project_name, representation_id):
|
|
@@ -52,7 +52,6 @@ from .constants import (
|
|
|
52
52
|
DEFAULT_EVENT_FIELDS,
|
|
53
53
|
DEFAULT_ACTIVITY_FIELDS,
|
|
54
54
|
DEFAULT_USER_FIELDS,
|
|
55
|
-
DEFAULT_LINK_FIELDS,
|
|
56
55
|
)
|
|
57
56
|
from .graphql import GraphQlQuery, INTROSPECTION_QUERY
|
|
58
57
|
from .graphql_queries import (
|
|
@@ -520,7 +519,7 @@ class ServerAPI(object):
|
|
|
520
519
|
self._server_version = None
|
|
521
520
|
self._server_version_tuple = None
|
|
522
521
|
|
|
523
|
-
self.
|
|
522
|
+
self._graphql_allows_traits_in_representations: Optional[bool] = None
|
|
524
523
|
|
|
525
524
|
self._session = None
|
|
526
525
|
|
|
@@ -1097,24 +1096,15 @@ class ServerAPI(object):
|
|
|
1097
1096
|
)
|
|
1098
1097
|
|
|
1099
1098
|
@property
|
|
1100
|
-
def
|
|
1101
|
-
"""
|
|
1102
|
-
|
|
1103
|
-
This applies only to project hierarchy entities 'project', 'folder',
|
|
1104
|
-
'task', 'product', 'version' and 'representation'. Others like 'user'
|
|
1105
|
-
still require to use rest api to access 'data'.
|
|
1106
|
-
|
|
1107
|
-
Returns:
|
|
1108
|
-
bool: True if server supports 'data' field in GraphQl query.
|
|
1109
|
-
|
|
1110
|
-
"""
|
|
1111
|
-
if self._graphql_allows_data_in_query is None:
|
|
1099
|
+
def graphql_allows_traits_in_representations(self) -> bool:
|
|
1100
|
+
"""Check server support for representation traits."""
|
|
1101
|
+
if self._graphql_allows_traits_in_representations is None:
|
|
1112
1102
|
major, minor, patch, _, _ = self.server_version_tuple
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1103
|
+
self._graphql_allows_traits_in_representations = (
|
|
1104
|
+
(major, minor, patch) >= (1, 7, 5)
|
|
1105
|
+
)
|
|
1106
|
+
return self._graphql_allows_traits_in_representations
|
|
1107
|
+
|
|
1118
1108
|
|
|
1119
1109
|
def _get_user_info(self) -> Optional[Dict[str, Any]]:
|
|
1120
1110
|
if self._access_token is None:
|
|
@@ -1143,6 +1133,7 @@ class ServerAPI(object):
|
|
|
1143
1133
|
self,
|
|
1144
1134
|
project_name: Optional[str] = None,
|
|
1145
1135
|
usernames: Optional[Iterable[str]] = None,
|
|
1136
|
+
emails: Optional[Iterable[str]] = None,
|
|
1146
1137
|
fields: Optional[Iterable[str]] = None,
|
|
1147
1138
|
) -> Generator[Dict[str, Any], None, None]:
|
|
1148
1139
|
"""Get Users.
|
|
@@ -1153,6 +1144,7 @@ class ServerAPI(object):
|
|
|
1153
1144
|
Args:
|
|
1154
1145
|
project_name (Optional[str]): Project name.
|
|
1155
1146
|
usernames (Optional[Iterable[str]]): Filter by usernames.
|
|
1147
|
+
emails (Optional[Iterable[str]]): Filter by emails.
|
|
1156
1148
|
fields (Optional[Iterable[str]]): Fields to be queried
|
|
1157
1149
|
for users.
|
|
1158
1150
|
|
|
@@ -1167,6 +1159,22 @@ class ServerAPI(object):
|
|
|
1167
1159
|
return
|
|
1168
1160
|
filters["userNames"] = list(usernames)
|
|
1169
1161
|
|
|
1162
|
+
if emails is not None:
|
|
1163
|
+
emails = set(emails)
|
|
1164
|
+
if not emails:
|
|
1165
|
+
return
|
|
1166
|
+
|
|
1167
|
+
major, minor, patch, _, _ = self.server_version_tuple
|
|
1168
|
+
emails_filter_available = (major, minor, patch) > (1, 7, 3)
|
|
1169
|
+
if not emails_filter_available:
|
|
1170
|
+
server_version = self.get_server_version()
|
|
1171
|
+
raise ValueError(
|
|
1172
|
+
"Filtering by emails is not supported by"
|
|
1173
|
+
f" server version {server_version}."
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1176
|
+
filters["emails"] = list(emails)
|
|
1177
|
+
|
|
1170
1178
|
if project_name is not None:
|
|
1171
1179
|
filters["projectName"] = project_name
|
|
1172
1180
|
|
|
@@ -1249,6 +1257,7 @@ class ServerAPI(object):
|
|
|
1249
1257
|
"Content-Type": content_type,
|
|
1250
1258
|
"x-ayon-platform": platform.system().lower(),
|
|
1251
1259
|
"x-ayon-hostname": platform.node(),
|
|
1260
|
+
"referer": self.get_base_url(),
|
|
1252
1261
|
}
|
|
1253
1262
|
if self._site_id is not None:
|
|
1254
1263
|
headers["x-ayon-site-id"] = self._site_id
|
|
@@ -1656,21 +1665,6 @@ class ServerAPI(object):
|
|
|
1656
1665
|
)
|
|
1657
1666
|
if value is not None
|
|
1658
1667
|
}
|
|
1659
|
-
# 'progress' and 'retries' are available since 0.5.x server version
|
|
1660
|
-
major, minor, _, _, _ = self.server_version_tuple
|
|
1661
|
-
if (major, minor) < (0, 5):
|
|
1662
|
-
args = []
|
|
1663
|
-
if progress is not None:
|
|
1664
|
-
args.append("progress")
|
|
1665
|
-
if retries is not None:
|
|
1666
|
-
args.append("retries")
|
|
1667
|
-
fields = ", ".join(f"'{f}'" for f in args)
|
|
1668
|
-
ending = "s" if len(args) > 1 else ""
|
|
1669
|
-
raise ValueError(
|
|
1670
|
-
f"Your server version '{self.server_version}' does not"
|
|
1671
|
-
f" support update of {fields} field{ending} on event."
|
|
1672
|
-
" The fields are supported since server version '0.5'."
|
|
1673
|
-
)
|
|
1674
1668
|
|
|
1675
1669
|
response = self.patch(
|
|
1676
1670
|
f"events/{event_id}",
|
|
@@ -2730,36 +2724,27 @@ class ServerAPI(object):
|
|
|
2730
2724
|
|
|
2731
2725
|
if entity_type == "project":
|
|
2732
2726
|
entity_type_defaults = set(DEFAULT_PROJECT_FIELDS)
|
|
2733
|
-
if not self.graphql_allows_data_in_query:
|
|
2734
|
-
entity_type_defaults.discard("data")
|
|
2735
2727
|
|
|
2736
2728
|
elif entity_type == "folder":
|
|
2737
2729
|
entity_type_defaults = set(DEFAULT_FOLDER_FIELDS)
|
|
2738
|
-
if not self.graphql_allows_data_in_query:
|
|
2739
|
-
entity_type_defaults.discard("data")
|
|
2740
2730
|
|
|
2741
2731
|
elif entity_type == "task":
|
|
2742
2732
|
entity_type_defaults = set(DEFAULT_TASK_FIELDS)
|
|
2743
|
-
if not self.graphql_allows_data_in_query:
|
|
2744
|
-
entity_type_defaults.discard("data")
|
|
2745
2733
|
|
|
2746
2734
|
elif entity_type == "product":
|
|
2747
2735
|
entity_type_defaults = set(DEFAULT_PRODUCT_FIELDS)
|
|
2748
|
-
if not self.graphql_allows_data_in_query:
|
|
2749
|
-
entity_type_defaults.discard("data")
|
|
2750
2736
|
|
|
2751
2737
|
elif entity_type == "version":
|
|
2752
2738
|
entity_type_defaults = set(DEFAULT_VERSION_FIELDS)
|
|
2753
|
-
if not self.graphql_allows_data_in_query:
|
|
2754
|
-
entity_type_defaults.discard("data")
|
|
2755
2739
|
|
|
2756
2740
|
elif entity_type == "representation":
|
|
2757
2741
|
entity_type_defaults = (
|
|
2758
2742
|
DEFAULT_REPRESENTATION_FIELDS
|
|
2759
2743
|
| REPRESENTATION_FILES_FIELDS
|
|
2760
2744
|
)
|
|
2761
|
-
|
|
2762
|
-
|
|
2745
|
+
|
|
2746
|
+
if not self.graphql_allows_traits_in_representations:
|
|
2747
|
+
entity_type_defaults.discard("traits")
|
|
2763
2748
|
|
|
2764
2749
|
elif entity_type == "folderType":
|
|
2765
2750
|
entity_type_defaults = set(DEFAULT_FOLDER_TYPE_FIELDS)
|
|
@@ -2772,8 +2757,6 @@ class ServerAPI(object):
|
|
|
2772
2757
|
|
|
2773
2758
|
elif entity_type == "workfile":
|
|
2774
2759
|
entity_type_defaults = set(DEFAULT_WORKFILE_INFO_FIELDS)
|
|
2775
|
-
if not self.graphql_allows_data_in_query:
|
|
2776
|
-
entity_type_defaults.discard("data")
|
|
2777
2760
|
|
|
2778
2761
|
elif entity_type == "user":
|
|
2779
2762
|
entity_type_defaults = set(DEFAULT_USER_FIELDS)
|
|
@@ -4646,10 +4629,14 @@ class ServerAPI(object):
|
|
|
4646
4629
|
return
|
|
4647
4630
|
|
|
4648
4631
|
self._prepare_fields("project", fields, own_attributes)
|
|
4632
|
+
if active is not None:
|
|
4633
|
+
fields.add("active")
|
|
4649
4634
|
|
|
4650
4635
|
query = projects_graphql_query(fields)
|
|
4651
4636
|
for parsed_data in query.continuous_query(self):
|
|
4652
4637
|
for project in parsed_data["projects"]:
|
|
4638
|
+
if active is not None and active is not project["active"]:
|
|
4639
|
+
continue
|
|
4653
4640
|
if own_attributes:
|
|
4654
4641
|
fill_own_attribs(project)
|
|
4655
4642
|
yield project
|
|
@@ -4930,15 +4917,10 @@ class ServerAPI(object):
|
|
|
4930
4917
|
fields = set(fields)
|
|
4931
4918
|
self._prepare_fields("folder", fields)
|
|
4932
4919
|
|
|
4933
|
-
use_rest = False
|
|
4934
|
-
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
4935
|
-
use_rest = True
|
|
4936
|
-
fields = {"id"}
|
|
4937
|
-
|
|
4938
4920
|
if active is not None:
|
|
4939
4921
|
fields.add("active")
|
|
4940
4922
|
|
|
4941
|
-
if own_attributes
|
|
4923
|
+
if own_attributes:
|
|
4942
4924
|
fields.add("ownAttrib")
|
|
4943
4925
|
|
|
4944
4926
|
query = folders_graphql_query(fields)
|
|
@@ -4950,10 +4932,7 @@ class ServerAPI(object):
|
|
|
4950
4932
|
if active is not None and active is not folder["active"]:
|
|
4951
4933
|
continue
|
|
4952
4934
|
|
|
4953
|
-
|
|
4954
|
-
folder = self.get_rest_folder(project_name, folder["id"])
|
|
4955
|
-
else:
|
|
4956
|
-
self._convert_entity_data(folder)
|
|
4935
|
+
self._convert_entity_data(folder)
|
|
4957
4936
|
|
|
4958
4937
|
if own_attributes:
|
|
4959
4938
|
fill_own_attribs(folder)
|
|
@@ -5325,11 +5304,6 @@ class ServerAPI(object):
|
|
|
5325
5304
|
fields = set(fields)
|
|
5326
5305
|
self._prepare_fields("task", fields, own_attributes)
|
|
5327
5306
|
|
|
5328
|
-
use_rest = False
|
|
5329
|
-
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
5330
|
-
use_rest = True
|
|
5331
|
-
fields = {"id"}
|
|
5332
|
-
|
|
5333
5307
|
if active is not None:
|
|
5334
5308
|
fields.add("active")
|
|
5335
5309
|
|
|
@@ -5342,10 +5316,7 @@ class ServerAPI(object):
|
|
|
5342
5316
|
if active is not None and active is not task["active"]:
|
|
5343
5317
|
continue
|
|
5344
5318
|
|
|
5345
|
-
|
|
5346
|
-
task = self.get_rest_task(project_name, task["id"])
|
|
5347
|
-
else:
|
|
5348
|
-
self._convert_entity_data(task)
|
|
5319
|
+
self._convert_entity_data(task)
|
|
5349
5320
|
|
|
5350
5321
|
if own_attributes:
|
|
5351
5322
|
fill_own_attribs(task)
|
|
@@ -5487,11 +5458,6 @@ class ServerAPI(object):
|
|
|
5487
5458
|
fields = set(fields)
|
|
5488
5459
|
self._prepare_fields("task", fields, own_attributes)
|
|
5489
5460
|
|
|
5490
|
-
use_rest = False
|
|
5491
|
-
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
5492
|
-
use_rest = True
|
|
5493
|
-
fields = {"id"}
|
|
5494
|
-
|
|
5495
5461
|
if active is not None:
|
|
5496
5462
|
fields.add("active")
|
|
5497
5463
|
|
|
@@ -5510,10 +5476,7 @@ class ServerAPI(object):
|
|
|
5510
5476
|
if active is not None and active is not task["active"]:
|
|
5511
5477
|
continue
|
|
5512
5478
|
|
|
5513
|
-
|
|
5514
|
-
task = self.get_rest_task(project_name, task["id"])
|
|
5515
|
-
else:
|
|
5516
|
-
self._convert_entity_data(task)
|
|
5479
|
+
self._convert_entity_data(task)
|
|
5517
5480
|
|
|
5518
5481
|
if own_attributes:
|
|
5519
5482
|
fill_own_attribs(task)
|
|
@@ -5763,15 +5726,11 @@ class ServerAPI(object):
|
|
|
5763
5726
|
project_name: str,
|
|
5764
5727
|
product: "ProductDict",
|
|
5765
5728
|
active: "Union[bool, None]",
|
|
5766
|
-
use_rest: bool,
|
|
5767
5729
|
) -> Optional["ProductDict"]:
|
|
5768
5730
|
if active is not None and product["active"] is not active:
|
|
5769
5731
|
return None
|
|
5770
5732
|
|
|
5771
|
-
|
|
5772
|
-
product = self.get_rest_product(project_name, product["id"])
|
|
5773
|
-
else:
|
|
5774
|
-
self._convert_entity_data(product)
|
|
5733
|
+
self._convert_entity_data(product)
|
|
5775
5734
|
|
|
5776
5735
|
return product
|
|
5777
5736
|
|
|
@@ -5864,11 +5823,6 @@ class ServerAPI(object):
|
|
|
5864
5823
|
else:
|
|
5865
5824
|
fields = self.get_default_fields_for_type("product")
|
|
5866
5825
|
|
|
5867
|
-
use_rest = False
|
|
5868
|
-
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
5869
|
-
use_rest = True
|
|
5870
|
-
fields = {"id"}
|
|
5871
|
-
|
|
5872
5826
|
if active is not None:
|
|
5873
5827
|
fields.add("active")
|
|
5874
5828
|
|
|
@@ -5926,7 +5880,7 @@ class ServerAPI(object):
|
|
|
5926
5880
|
products_by_folder_id = collections.defaultdict(list)
|
|
5927
5881
|
for product in products:
|
|
5928
5882
|
filtered_product = self._filter_product(
|
|
5929
|
-
project_name, product, active
|
|
5883
|
+
project_name, product, active
|
|
5930
5884
|
)
|
|
5931
5885
|
if filtered_product is not None:
|
|
5932
5886
|
folder_id = filtered_product["folderId"]
|
|
@@ -5940,7 +5894,7 @@ class ServerAPI(object):
|
|
|
5940
5894
|
else:
|
|
5941
5895
|
for product in products:
|
|
5942
5896
|
filtered_product = self._filter_product(
|
|
5943
|
-
project_name, product, active
|
|
5897
|
+
project_name, product, active
|
|
5944
5898
|
)
|
|
5945
5899
|
if filtered_product is not None:
|
|
5946
5900
|
yield filtered_product
|
|
@@ -6287,11 +6241,6 @@ class ServerAPI(object):
|
|
|
6287
6241
|
# Make sure fields have minimum required fields
|
|
6288
6242
|
fields |= {"id", "version"}
|
|
6289
6243
|
|
|
6290
|
-
use_rest = False
|
|
6291
|
-
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
6292
|
-
use_rest = True
|
|
6293
|
-
fields = {"id"}
|
|
6294
|
-
|
|
6295
6244
|
if active is not None:
|
|
6296
6245
|
fields.add("active")
|
|
6297
6246
|
|
|
@@ -6364,12 +6313,7 @@ class ServerAPI(object):
|
|
|
6364
6313
|
if not hero and version["version"] < 0:
|
|
6365
6314
|
continue
|
|
6366
6315
|
|
|
6367
|
-
|
|
6368
|
-
version = self.get_rest_version(
|
|
6369
|
-
project_name, version["id"]
|
|
6370
|
-
)
|
|
6371
|
-
else:
|
|
6372
|
-
self._convert_entity_data(version)
|
|
6316
|
+
self._convert_entity_data(version)
|
|
6373
6317
|
|
|
6374
6318
|
yield version
|
|
6375
6319
|
|
|
@@ -6931,11 +6875,6 @@ class ServerAPI(object):
|
|
|
6931
6875
|
fields = set(fields)
|
|
6932
6876
|
self._prepare_fields("representation", fields)
|
|
6933
6877
|
|
|
6934
|
-
use_rest = False
|
|
6935
|
-
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
6936
|
-
use_rest = True
|
|
6937
|
-
fields = {"id"}
|
|
6938
|
-
|
|
6939
6878
|
if active is not None:
|
|
6940
6879
|
fields.add("active")
|
|
6941
6880
|
|
|
@@ -7017,12 +6956,7 @@ class ServerAPI(object):
|
|
|
7017
6956
|
if active is not None and active is not repre["active"]:
|
|
7018
6957
|
continue
|
|
7019
6958
|
|
|
7020
|
-
|
|
7021
|
-
repre = self.get_rest_representation(
|
|
7022
|
-
project_name, repre["id"]
|
|
7023
|
-
)
|
|
7024
|
-
else:
|
|
7025
|
-
self._convert_entity_data(repre)
|
|
6959
|
+
self._convert_entity_data(repre)
|
|
7026
6960
|
|
|
7027
6961
|
self._representation_conversion(repre)
|
|
7028
6962
|
|
|
@@ -7452,6 +7386,7 @@ class ServerAPI(object):
|
|
|
7452
7386
|
files: Optional[List[Dict[str, Any]]] = None,
|
|
7453
7387
|
attrib: Optional[Dict[str, Any]] = None,
|
|
7454
7388
|
data: Optional[Dict[str, Any]] = None,
|
|
7389
|
+
traits: Optional[Dict[str, Any]] = None,
|
|
7455
7390
|
tags: Optional[List[str]]=None,
|
|
7456
7391
|
status: Optional[str] = None,
|
|
7457
7392
|
active: Optional[bool] = None,
|
|
@@ -7466,6 +7401,8 @@ class ServerAPI(object):
|
|
|
7466
7401
|
files (Optional[list[dict]]): Representation files information.
|
|
7467
7402
|
attrib (Optional[dict[str, Any]]): Representation attributes.
|
|
7468
7403
|
data (Optional[dict[str, Any]]): Representation data.
|
|
7404
|
+
traits (Optional[dict[str, Any]]): Representation traits
|
|
7405
|
+
serialized data as dict.
|
|
7469
7406
|
tags (Optional[Iterable[str]]): Representation tags.
|
|
7470
7407
|
status (Optional[str]): Representation status.
|
|
7471
7408
|
active (Optional[bool]): Representation active state.
|
|
@@ -7487,6 +7424,7 @@ class ServerAPI(object):
|
|
|
7487
7424
|
("files", files),
|
|
7488
7425
|
("attrib", attrib),
|
|
7489
7426
|
("data", data),
|
|
7427
|
+
("traits", traits),
|
|
7490
7428
|
("tags", tags),
|
|
7491
7429
|
("status", status),
|
|
7492
7430
|
("active", active),
|
|
@@ -7510,6 +7448,7 @@ class ServerAPI(object):
|
|
|
7510
7448
|
files: Optional[List[Dict[str, Any]]] = None,
|
|
7511
7449
|
attrib: Optional[Dict[str, Any]] = None,
|
|
7512
7450
|
data: Optional[Dict[str, Any]] = None,
|
|
7451
|
+
traits: Optional[Dict[str, Any]] = None,
|
|
7513
7452
|
tags: Optional[List[str]] = None,
|
|
7514
7453
|
status: Optional[str] = None,
|
|
7515
7454
|
active: Optional[bool] = None,
|
|
@@ -7530,6 +7469,7 @@ class ServerAPI(object):
|
|
|
7530
7469
|
information.
|
|
7531
7470
|
attrib (Optional[dict[str, Any]]): New attributes.
|
|
7532
7471
|
data (Optional[dict[str, Any]]): New data.
|
|
7472
|
+
traits (Optional[dict[str, Any]]): New traits.
|
|
7533
7473
|
tags (Optional[Iterable[str]]): New tags.
|
|
7534
7474
|
status (Optional[str]): New status.
|
|
7535
7475
|
active (Optional[bool]): New active state.
|
|
@@ -7542,6 +7482,7 @@ class ServerAPI(object):
|
|
|
7542
7482
|
("files", files),
|
|
7543
7483
|
("attrib", attrib),
|
|
7544
7484
|
("data", data),
|
|
7485
|
+
("traits", traits),
|
|
7545
7486
|
("tags", tags),
|
|
7546
7487
|
("status", status),
|
|
7547
7488
|
("active", active),
|
|
@@ -7765,9 +7706,10 @@ class ServerAPI(object):
|
|
|
7765
7706
|
) -> ThumbnailContent:
|
|
7766
7707
|
"""Get thumbnail from server by id.
|
|
7767
7708
|
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7709
|
+
Warnings:
|
|
7710
|
+
Please keep in mind that used endpoint is allowed only for admins
|
|
7711
|
+
and managers. Use 'get_thumbnail' with entity type and id
|
|
7712
|
+
to allow access for artists.
|
|
7771
7713
|
|
|
7772
7714
|
Notes:
|
|
7773
7715
|
It is recommended to use one of prepared entity type specific
|
|
@@ -7802,7 +7744,7 @@ class ServerAPI(object):
|
|
|
7802
7744
|
"""Get thumbnail from server.
|
|
7803
7745
|
|
|
7804
7746
|
Permissions of thumbnails are related to entities so thumbnails must
|
|
7805
|
-
be queried per entity. So an entity type and entity
|
|
7747
|
+
be queried per entity. So an entity type and entity id is required
|
|
7806
7748
|
to be passed.
|
|
7807
7749
|
|
|
7808
7750
|
Notes:
|
|
@@ -7826,10 +7768,17 @@ class ServerAPI(object):
|
|
|
7826
7768
|
|
|
7827
7769
|
"""
|
|
7828
7770
|
if thumbnail_id:
|
|
7829
|
-
|
|
7771
|
+
warnings.warn(
|
|
7772
|
+
(
|
|
7773
|
+
"Function 'get_thumbnail' got 'thumbnail_id' which"
|
|
7774
|
+
" is deprecated and will be removed in future version."
|
|
7775
|
+
),
|
|
7776
|
+
DeprecationWarning
|
|
7777
|
+
)
|
|
7830
7778
|
|
|
7831
7779
|
if entity_type in (
|
|
7832
7780
|
"folder",
|
|
7781
|
+
"task",
|
|
7833
7782
|
"version",
|
|
7834
7783
|
"workfile",
|
|
7835
7784
|
):
|
|
@@ -7859,10 +7808,36 @@ class ServerAPI(object):
|
|
|
7859
7808
|
valid.
|
|
7860
7809
|
|
|
7861
7810
|
"""
|
|
7811
|
+
if thumbnail_id:
|
|
7812
|
+
warnings.warn(
|
|
7813
|
+
(
|
|
7814
|
+
"Function 'get_folder_thumbnail' got 'thumbnail_id' which"
|
|
7815
|
+
" is deprecated and will be removed in future version."
|
|
7816
|
+
),
|
|
7817
|
+
DeprecationWarning
|
|
7818
|
+
)
|
|
7862
7819
|
return self.get_thumbnail(
|
|
7863
|
-
project_name, "folder", folder_id
|
|
7820
|
+
project_name, "folder", folder_id
|
|
7864
7821
|
)
|
|
7865
7822
|
|
|
7823
|
+
def get_task_thumbnail(
|
|
7824
|
+
self,
|
|
7825
|
+
project_name: str,
|
|
7826
|
+
task_id: str,
|
|
7827
|
+
) -> ThumbnailContent:
|
|
7828
|
+
"""Prepared method to receive thumbnail for task entity.
|
|
7829
|
+
|
|
7830
|
+
Args:
|
|
7831
|
+
project_name (str): Project under which the entity is located.
|
|
7832
|
+
task_id (str): Folder id for which thumbnail should be returned.
|
|
7833
|
+
|
|
7834
|
+
Returns:
|
|
7835
|
+
ThumbnailContent: Thumbnail content wrapper. Does not have to be
|
|
7836
|
+
valid.
|
|
7837
|
+
|
|
7838
|
+
"""
|
|
7839
|
+
return self.get_thumbnail(project_name, "task", task_id)
|
|
7840
|
+
|
|
7866
7841
|
def get_version_thumbnail(
|
|
7867
7842
|
self,
|
|
7868
7843
|
project_name: str,
|
|
@@ -7883,8 +7858,16 @@ class ServerAPI(object):
|
|
|
7883
7858
|
valid.
|
|
7884
7859
|
|
|
7885
7860
|
"""
|
|
7861
|
+
if thumbnail_id:
|
|
7862
|
+
warnings.warn(
|
|
7863
|
+
(
|
|
7864
|
+
"Function 'get_version_thumbnail' got 'thumbnail_id' which"
|
|
7865
|
+
" is deprecated and will be removed in future version."
|
|
7866
|
+
),
|
|
7867
|
+
DeprecationWarning
|
|
7868
|
+
)
|
|
7886
7869
|
return self.get_thumbnail(
|
|
7887
|
-
project_name, "version", version_id
|
|
7870
|
+
project_name, "version", version_id
|
|
7888
7871
|
)
|
|
7889
7872
|
|
|
7890
7873
|
def get_workfile_thumbnail(
|
|
@@ -7907,8 +7890,17 @@ class ServerAPI(object):
|
|
|
7907
7890
|
valid.
|
|
7908
7891
|
|
|
7909
7892
|
"""
|
|
7893
|
+
if thumbnail_id:
|
|
7894
|
+
warnings.warn(
|
|
7895
|
+
(
|
|
7896
|
+
"Function 'get_workfile_thumbnail' got 'thumbnail_id'"
|
|
7897
|
+
" which is deprecated and will be removed in future"
|
|
7898
|
+
" version."
|
|
7899
|
+
),
|
|
7900
|
+
DeprecationWarning
|
|
7901
|
+
)
|
|
7910
7902
|
return self.get_thumbnail(
|
|
7911
|
-
project_name, "workfile", workfile_id
|
|
7903
|
+
project_name, "workfile", workfile_id
|
|
7912
7904
|
)
|
|
7913
7905
|
|
|
7914
7906
|
def create_thumbnail(
|
|
@@ -8345,22 +8337,8 @@ class ServerAPI(object):
|
|
|
8345
8337
|
kwargs = {
|
|
8346
8338
|
"input": input_id,
|
|
8347
8339
|
"output": output_id,
|
|
8340
|
+
"linkType": full_link_type_name,
|
|
8348
8341
|
}
|
|
8349
|
-
major, minor, patch, rel, _ = self.server_version_tuple
|
|
8350
|
-
rel_regex = re.compile(r"rc\.[0-5]")
|
|
8351
|
-
if (
|
|
8352
|
-
((major, minor, patch) == (1, 0, 0) and rel_regex.match(rel))
|
|
8353
|
-
or (major, minor, patch) < (1, 0, 0)
|
|
8354
|
-
):
|
|
8355
|
-
kwargs["link"] = full_link_type_name
|
|
8356
|
-
if link_name:
|
|
8357
|
-
raise UnsupportedServerVersion(
|
|
8358
|
-
"Link name is not supported"
|
|
8359
|
-
f" for version of AYON server {self.server_version}"
|
|
8360
|
-
)
|
|
8361
|
-
else:
|
|
8362
|
-
kwargs["linkType"] = full_link_type_name
|
|
8363
|
-
|
|
8364
8342
|
if link_name:
|
|
8365
8343
|
kwargs["name"] = link_name
|
|
8366
8344
|
|
|
@@ -8522,23 +8500,6 @@ class ServerAPI(object):
|
|
|
8522
8500
|
return output
|
|
8523
8501
|
|
|
8524
8502
|
link_fields = {"id", "links"}
|
|
8525
|
-
# Backwards compatibility for server version 1.0.0-rc.5 and lower
|
|
8526
|
-
# ---------
|
|
8527
|
-
major, minor, patch, rel, _ = self.server_version_tuple
|
|
8528
|
-
rel_regex = re.compile(r"rc\.[0-5]")
|
|
8529
|
-
if (
|
|
8530
|
-
((major, minor, patch) == (1, 0, 0) and rel_regex.match(rel))
|
|
8531
|
-
or (major, minor, patch) < (1, 0, 0)
|
|
8532
|
-
):
|
|
8533
|
-
fields = set(DEFAULT_LINK_FIELDS)
|
|
8534
|
-
fields.discard("name")
|
|
8535
|
-
link_fields.discard("links")
|
|
8536
|
-
link_fields |= {
|
|
8537
|
-
f"links.{field}"
|
|
8538
|
-
for field in fields
|
|
8539
|
-
}
|
|
8540
|
-
# ---------
|
|
8541
|
-
|
|
8542
8503
|
query = query_func(link_fields)
|
|
8543
8504
|
for attr, filter_value in filters.items():
|
|
8544
8505
|
query.set_variable_value(attr, filter_value)
|
|
@@ -4,6 +4,7 @@ import datetime
|
|
|
4
4
|
import uuid
|
|
5
5
|
import string
|
|
6
6
|
import platform
|
|
7
|
+
import traceback
|
|
7
8
|
import collections
|
|
8
9
|
from urllib.parse import urlparse, urlencode
|
|
9
10
|
import typing
|
|
@@ -322,18 +323,38 @@ def _try_parse_url(url: str) -> Optional[str]:
|
|
|
322
323
|
|
|
323
324
|
|
|
324
325
|
def _try_connect_to_server(
|
|
325
|
-
url: str,
|
|
326
|
-
|
|
326
|
+
url: str,
|
|
327
|
+
timeout: Optional[float],
|
|
328
|
+
verify: Optional["Union[str, bool]"],
|
|
329
|
+
cert: Optional[str],
|
|
330
|
+
) -> Optional[str]:
|
|
327
331
|
if timeout is None:
|
|
328
332
|
timeout = get_default_timeout()
|
|
333
|
+
|
|
334
|
+
if verify is None:
|
|
335
|
+
verify = os.environ.get("AYON_CA_FILE") or True
|
|
336
|
+
|
|
337
|
+
if cert is None:
|
|
338
|
+
cert = os.environ.get("AYON_CERT_FILE") or None
|
|
339
|
+
|
|
329
340
|
try:
|
|
330
341
|
# TODO add validation if the url lead to AYON server
|
|
331
342
|
# - this won't validate if the url lead to 'google.com'
|
|
332
|
-
requests.get(
|
|
343
|
+
response = requests.get(
|
|
344
|
+
url,
|
|
345
|
+
timeout=timeout,
|
|
346
|
+
verify=verify,
|
|
347
|
+
cert=cert,
|
|
348
|
+
)
|
|
349
|
+
if response.history:
|
|
350
|
+
return response.history[-1].headers["location"].rstrip("/")
|
|
351
|
+
return url
|
|
333
352
|
|
|
334
|
-
except
|
|
335
|
-
|
|
336
|
-
|
|
353
|
+
except Exception:
|
|
354
|
+
print(f"Failed to connect to '{url}'")
|
|
355
|
+
traceback.print_exc()
|
|
356
|
+
|
|
357
|
+
return None
|
|
337
358
|
|
|
338
359
|
|
|
339
360
|
def login_to_server(
|
|
@@ -463,7 +484,12 @@ def is_token_valid(
|
|
|
463
484
|
return False
|
|
464
485
|
|
|
465
486
|
|
|
466
|
-
def validate_url(
|
|
487
|
+
def validate_url(
|
|
488
|
+
url: str,
|
|
489
|
+
timeout: Optional[int] = None,
|
|
490
|
+
verify: Optional["Union[str, bool]"] = None,
|
|
491
|
+
cert: Optional[str] = None,
|
|
492
|
+
) -> str:
|
|
467
493
|
"""Validate url if is valid and server is available.
|
|
468
494
|
|
|
469
495
|
Validation checks if can be parsed as url and contains scheme.
|
|
@@ -520,12 +546,23 @@ def validate_url(url: str, timeout: Optional[int] = None) -> str:
|
|
|
520
546
|
# Try add 'https://' scheme if is missing
|
|
521
547
|
# - this will trigger UrlError if both will crash
|
|
522
548
|
if not parsed_url.scheme:
|
|
523
|
-
new_url =
|
|
524
|
-
|
|
549
|
+
new_url = _try_connect_to_server(
|
|
550
|
+
"http://" + modified_url,
|
|
551
|
+
timeout=timeout,
|
|
552
|
+
verify=verify,
|
|
553
|
+
cert=cert,
|
|
554
|
+
)
|
|
555
|
+
if new_url:
|
|
525
556
|
return new_url
|
|
526
557
|
|
|
527
|
-
|
|
528
|
-
|
|
558
|
+
new_url = _try_connect_to_server(
|
|
559
|
+
modified_url,
|
|
560
|
+
timeout=timeout,
|
|
561
|
+
verify=verify,
|
|
562
|
+
cert=cert,
|
|
563
|
+
)
|
|
564
|
+
if new_url:
|
|
565
|
+
return new_url
|
|
529
566
|
|
|
530
567
|
hints = []
|
|
531
568
|
if "/" in parsed_url.path or not parsed_url.scheme:
|
|
@@ -855,11 +892,13 @@ def _get_media_mime_type_for_content_base(content: bytes) -> Optional[str]:
|
|
|
855
892
|
if content[0:4] == b"\211PNG":
|
|
856
893
|
return "image/png"
|
|
857
894
|
|
|
858
|
-
# JPEG
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
)
|
|
895
|
+
# JPEG
|
|
896
|
+
# - [0:2] is constant b"\xff\xd8"
|
|
897
|
+
# (ref. https://www.file-recovery.com/jpg-signature-format.htm)
|
|
898
|
+
# - [2:4] Marker identifier b"\xff{?}"
|
|
899
|
+
# (ref. https://www.disktuna.com/list-of-jpeg-markers/)
|
|
900
|
+
# NOTE: File ends with b"\xff\xd9"
|
|
901
|
+
if content[0:3] == b"\xff\xd8\xff":
|
|
863
902
|
return "image/jpeg"
|
|
864
903
|
|
|
865
904
|
# Webp
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Package declaring Python API for AYON server."""
|
|
2
|
-
__version__ = "1.
|
|
2
|
+
__version__ = "1.1.1"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ayon-python-api"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.1.1"
|
|
4
4
|
description = "AYON Python API"
|
|
5
5
|
license = {file = "LICENSE"}
|
|
6
6
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
@@ -16,7 +16,6 @@ classifiers = [
|
|
|
16
16
|
dependencies = [
|
|
17
17
|
"requests >= 2.27.1",
|
|
18
18
|
"Unidecode >= 1.3.0",
|
|
19
|
-
"appdirs >=1, <2",
|
|
20
19
|
]
|
|
21
20
|
|
|
22
21
|
[project.urls]
|
|
@@ -29,7 +28,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
29
28
|
|
|
30
29
|
[tool.poetry]
|
|
31
30
|
name = "ayon-python-api"
|
|
32
|
-
version = "1.
|
|
31
|
+
version = "1.1.1"
|
|
33
32
|
description = "AYON Python API"
|
|
34
33
|
authors = [
|
|
35
34
|
"ynput.io <info@ynput.io>"
|
|
@@ -42,7 +41,6 @@ packages = [
|
|
|
42
41
|
python = ">=3.6.5"
|
|
43
42
|
requests = "^2.27"
|
|
44
43
|
Unidecode = "^1.3"
|
|
45
|
-
appdirs = "^1.4"
|
|
46
44
|
|
|
47
45
|
[tool.poetry.group.dev.dependencies]
|
|
48
46
|
sphinx = "*"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ayon-python-api-1.0.12 → ayon-python-api-1.1.1}/ayon_python_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|