ayon-python-api 1.0.6__tar.gz → 1.0.8__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.6 → ayon-python-api-1.0.8}/PKG-INFO +1 -1
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/__init__.py +12 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/_api.py +61 -1
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/graphql_queries.py +9 -1
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/server_api.py +151 -12
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/utils.py +146 -7
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/version.py +1 -1
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_python_api.egg-info/PKG-INFO +1 -1
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/pyproject.toml +2 -2
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/LICENSE +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/README.md +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/constants.py +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/entity_hub.py +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/events.py +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/exceptions.py +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/graphql.py +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_api/operations.py +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_python_api.egg-info/SOURCES.txt +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_python_api.egg-info/dependency_links.txt +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_python_api.egg-info/requires.txt +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/ayon_python_api.egg-info/top_level.txt +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/setup.cfg +0 -0
- {ayon-python-api-1.0.6 → ayon-python-api-1.0.8}/setup.py +0 -0
|
@@ -3,6 +3,10 @@ from .utils import (
|
|
|
3
3
|
TransferProgress,
|
|
4
4
|
slugify_string,
|
|
5
5
|
create_dependency_package_basename,
|
|
6
|
+
get_user_by_token,
|
|
7
|
+
is_token_valid,
|
|
8
|
+
validate_url,
|
|
9
|
+
login_to_server,
|
|
6
10
|
)
|
|
7
11
|
from .server_api import (
|
|
8
12
|
RequestTypes,
|
|
@@ -46,6 +50,7 @@ from ._api import (
|
|
|
46
50
|
get_server_version,
|
|
47
51
|
get_server_version_tuple,
|
|
48
52
|
get_users,
|
|
53
|
+
get_user_by_name,
|
|
49
54
|
get_user,
|
|
50
55
|
raw_post,
|
|
51
56
|
raw_put,
|
|
@@ -66,6 +71,7 @@ from ._api import (
|
|
|
66
71
|
download_file,
|
|
67
72
|
upload_file_from_stream,
|
|
68
73
|
upload_file,
|
|
74
|
+
upload_reviewable,
|
|
69
75
|
trigger_server_restart,
|
|
70
76
|
query_graphql,
|
|
71
77
|
get_graphql_schema,
|
|
@@ -228,6 +234,10 @@ __all__ = (
|
|
|
228
234
|
"TransferProgress",
|
|
229
235
|
"slugify_string",
|
|
230
236
|
"create_dependency_package_basename",
|
|
237
|
+
"get_user_by_token",
|
|
238
|
+
"is_token_valid",
|
|
239
|
+
"validate_url",
|
|
240
|
+
"login_to_server",
|
|
231
241
|
|
|
232
242
|
"RequestTypes",
|
|
233
243
|
"ServerAPI",
|
|
@@ -268,6 +278,7 @@ __all__ = (
|
|
|
268
278
|
"get_server_version",
|
|
269
279
|
"get_server_version_tuple",
|
|
270
280
|
"get_users",
|
|
281
|
+
"get_user_by_name",
|
|
271
282
|
"get_user",
|
|
272
283
|
"raw_post",
|
|
273
284
|
"raw_put",
|
|
@@ -288,6 +299,7 @@ __all__ = (
|
|
|
288
299
|
"download_file",
|
|
289
300
|
"upload_file_from_stream",
|
|
290
301
|
"upload_file",
|
|
302
|
+
"upload_reviewable",
|
|
291
303
|
"trigger_server_restart",
|
|
292
304
|
"query_graphql",
|
|
293
305
|
"get_graphql_schema",
|
|
@@ -594,9 +594,13 @@ def get_server_version_tuple():
|
|
|
594
594
|
def get_users(*args, **kwargs):
|
|
595
595
|
"""Get Users.
|
|
596
596
|
|
|
597
|
+
Only administrators and managers can fetch all users. For other users
|
|
598
|
+
it is required to pass in 'project_name' filter.
|
|
599
|
+
|
|
597
600
|
Args:
|
|
601
|
+
project_name (Optional[str]): Project name.
|
|
598
602
|
usernames (Optional[Iterable[str]]): Filter by usernames.
|
|
599
|
-
fields (Optional[Iterable[str]]):
|
|
603
|
+
fields (Optional[Iterable[str]]): Fields to be queried
|
|
600
604
|
for users.
|
|
601
605
|
|
|
602
606
|
Returns:
|
|
@@ -607,7 +611,38 @@ def get_users(*args, **kwargs):
|
|
|
607
611
|
return con.get_users(*args, **kwargs)
|
|
608
612
|
|
|
609
613
|
|
|
614
|
+
def get_user_by_name(*args, **kwargs):
|
|
615
|
+
"""Get user by name using GraphQl.
|
|
616
|
+
|
|
617
|
+
Only administrators and managers can fetch all users. For other users
|
|
618
|
+
it is required to pass in 'project_name' filter.
|
|
619
|
+
|
|
620
|
+
Args:
|
|
621
|
+
username (str): Username.
|
|
622
|
+
project_name (Optional[str]): Define scope of project.
|
|
623
|
+
fields (Optional[Iterable[str]]): Fields to be queried
|
|
624
|
+
for users.
|
|
625
|
+
|
|
626
|
+
Returns:
|
|
627
|
+
Union[dict[str, Any], None]: User info or None if user is not
|
|
628
|
+
found.
|
|
629
|
+
|
|
630
|
+
"""
|
|
631
|
+
con = get_server_api_connection()
|
|
632
|
+
return con.get_user_by_name(*args, **kwargs)
|
|
633
|
+
|
|
634
|
+
|
|
610
635
|
def get_user(*args, **kwargs):
|
|
636
|
+
"""Get user info using REST endpoit.
|
|
637
|
+
|
|
638
|
+
Args:
|
|
639
|
+
username (Optional[str]): Username.
|
|
640
|
+
|
|
641
|
+
Returns:
|
|
642
|
+
Union[dict[str, Any], None]: User info or None if user is not
|
|
643
|
+
found.
|
|
644
|
+
|
|
645
|
+
"""
|
|
611
646
|
con = get_server_api_connection()
|
|
612
647
|
return con.get_user(*args, **kwargs)
|
|
613
648
|
|
|
@@ -903,6 +938,29 @@ def upload_file(*args, **kwargs):
|
|
|
903
938
|
return con.upload_file(*args, **kwargs)
|
|
904
939
|
|
|
905
940
|
|
|
941
|
+
def upload_reviewable(*args, **kwargs):
|
|
942
|
+
"""Upload reviewable file to server.
|
|
943
|
+
|
|
944
|
+
Args:
|
|
945
|
+
project_name (str): Project name.
|
|
946
|
+
version_id (str): Version id.
|
|
947
|
+
filepath (str): Reviewable file path to upload.
|
|
948
|
+
label (Optional[str]): Reviewable label. Filled automatically
|
|
949
|
+
server side with filename.
|
|
950
|
+
content_type (Optional[str]): MIME type of the file.
|
|
951
|
+
filename (Optional[str]): User as original filename. Filename from
|
|
952
|
+
'filepath' is used when not filled.
|
|
953
|
+
progress (Optional[TransferProgress]): Progress.
|
|
954
|
+
headers (Optional[Dict[str, Any]]): Headers.
|
|
955
|
+
|
|
956
|
+
Returns:
|
|
957
|
+
RestApiResponse: Server response.
|
|
958
|
+
|
|
959
|
+
"""
|
|
960
|
+
con = get_server_api_connection()
|
|
961
|
+
return con.upload_reviewable(*args, **kwargs)
|
|
962
|
+
|
|
963
|
+
|
|
906
964
|
def trigger_server_restart():
|
|
907
965
|
"""Trigger server restart.
|
|
908
966
|
|
|
@@ -3310,6 +3368,7 @@ def get_representations_hierarchy(*args, **kwargs):
|
|
|
3310
3368
|
representation_ids (Iterable[str]): Representation ids.
|
|
3311
3369
|
project_fields (Optional[Iterable[str]]): Project fields.
|
|
3312
3370
|
folder_fields (Optional[Iterable[str]]): Folder fields.
|
|
3371
|
+
task_fields (Optional[Iterable[str]]): Task fields.
|
|
3313
3372
|
product_fields (Optional[Iterable[str]]): Product fields.
|
|
3314
3373
|
version_fields (Optional[Iterable[str]]): Version fields.
|
|
3315
3374
|
representation_fields (Optional[Iterable[str]]): Representation
|
|
@@ -3334,6 +3393,7 @@ def get_representation_hierarchy(*args, **kwargs):
|
|
|
3334
3393
|
representation_id (str): Representation id.
|
|
3335
3394
|
project_fields (Optional[Iterable[str]]): Project fields.
|
|
3336
3395
|
folder_fields (Optional[Iterable[str]]): Folder fields.
|
|
3396
|
+
task_fields (Optional[Iterable[str]]): Task fields.
|
|
3337
3397
|
product_fields (Optional[Iterable[str]]): Product fields.
|
|
3338
3398
|
version_fields (Optional[Iterable[str]]): Version fields.
|
|
3339
3399
|
representation_fields (Optional[Iterable[str]]): Representation
|
|
@@ -466,6 +466,7 @@ def representations_parents_qraphql_query(
|
|
|
466
466
|
|
|
467
467
|
def representations_hierarchy_qraphql_query(
|
|
468
468
|
folder_fields,
|
|
469
|
+
task_fields,
|
|
469
470
|
product_fields,
|
|
470
471
|
version_fields,
|
|
471
472
|
representation_fields,
|
|
@@ -486,12 +487,17 @@ def representations_hierarchy_qraphql_query(
|
|
|
486
487
|
|
|
487
488
|
repres_field.set_filter("ids", repre_ids_var)
|
|
488
489
|
version_field = None
|
|
489
|
-
if folder_fields or product_fields or version_fields:
|
|
490
|
+
if folder_fields or task_fields or product_fields or version_fields:
|
|
490
491
|
version_field = repres_field.add_field("version")
|
|
491
492
|
if version_fields:
|
|
492
493
|
for key, value in fields_to_dict(version_fields).items():
|
|
493
494
|
fields_queue.append((key, value, version_field))
|
|
494
495
|
|
|
496
|
+
if task_fields:
|
|
497
|
+
task_field = version_field.add_field("task")
|
|
498
|
+
for key, value in fields_to_dict(task_fields).items():
|
|
499
|
+
fields_queue.append((key, value, task_field))
|
|
500
|
+
|
|
495
501
|
product_field = None
|
|
496
502
|
if folder_fields or product_fields:
|
|
497
503
|
product_field = version_field.add_field("product")
|
|
@@ -600,9 +606,11 @@ def events_graphql_query(fields):
|
|
|
600
606
|
def users_graphql_query(fields):
|
|
601
607
|
query = GraphQlQuery("Users")
|
|
602
608
|
names_var = query.add_variable("userNames", "[String!]")
|
|
609
|
+
project_name_var = query.add_variable("projectName", "String!")
|
|
603
610
|
|
|
604
611
|
users_field = query.add_field_with_edges("users")
|
|
605
612
|
users_field.set_filter("names", names_var)
|
|
613
|
+
users_field.set_filter("projectName", project_name_var)
|
|
606
614
|
|
|
607
615
|
nested_fields = fields_to_dict(set(fields))
|
|
608
616
|
|
|
@@ -90,6 +90,7 @@ from .utils import (
|
|
|
90
90
|
get_default_settings_variant,
|
|
91
91
|
get_default_site_id,
|
|
92
92
|
NOT_SET,
|
|
93
|
+
get_media_mime_type,
|
|
93
94
|
)
|
|
94
95
|
|
|
95
96
|
PatternType = type(re.compile(""))
|
|
@@ -1028,12 +1029,16 @@ class ServerAPI(object):
|
|
|
1028
1029
|
self._access_token_is_service = None
|
|
1029
1030
|
return None
|
|
1030
1031
|
|
|
1031
|
-
def get_users(self, usernames=None, fields=None):
|
|
1032
|
+
def get_users(self, project_name=None, usernames=None, fields=None):
|
|
1032
1033
|
"""Get Users.
|
|
1033
1034
|
|
|
1035
|
+
Only administrators and managers can fetch all users. For other users
|
|
1036
|
+
it is required to pass in 'project_name' filter.
|
|
1037
|
+
|
|
1034
1038
|
Args:
|
|
1039
|
+
project_name (Optional[str]): Project name.
|
|
1035
1040
|
usernames (Optional[Iterable[str]]): Filter by usernames.
|
|
1036
|
-
fields (Optional[Iterable[str]]):
|
|
1041
|
+
fields (Optional[Iterable[str]]): Fields to be queried
|
|
1037
1042
|
for users.
|
|
1038
1043
|
|
|
1039
1044
|
Returns:
|
|
@@ -1047,6 +1052,9 @@ class ServerAPI(object):
|
|
|
1047
1052
|
return
|
|
1048
1053
|
filters["userNames"] = list(usernames)
|
|
1049
1054
|
|
|
1055
|
+
if project_name is not None:
|
|
1056
|
+
filters["projectName"] = project_name
|
|
1057
|
+
|
|
1050
1058
|
if not fields:
|
|
1051
1059
|
fields = self.get_default_fields_for_type("user")
|
|
1052
1060
|
|
|
@@ -1060,7 +1068,45 @@ class ServerAPI(object):
|
|
|
1060
1068
|
user["accessGroups"])
|
|
1061
1069
|
yield user
|
|
1062
1070
|
|
|
1071
|
+
def get_user_by_name(self, username, project_name=None, fields=None):
|
|
1072
|
+
"""Get user by name using GraphQl.
|
|
1073
|
+
|
|
1074
|
+
Only administrators and managers can fetch all users. For other users
|
|
1075
|
+
it is required to pass in 'project_name' filter.
|
|
1076
|
+
|
|
1077
|
+
Args:
|
|
1078
|
+
username (str): Username.
|
|
1079
|
+
project_name (Optional[str]): Define scope of project.
|
|
1080
|
+
fields (Optional[Iterable[str]]): Fields to be queried
|
|
1081
|
+
for users.
|
|
1082
|
+
|
|
1083
|
+
Returns:
|
|
1084
|
+
Union[dict[str, Any], None]: User info or None if user is not
|
|
1085
|
+
found.
|
|
1086
|
+
|
|
1087
|
+
"""
|
|
1088
|
+
if not username:
|
|
1089
|
+
return None
|
|
1090
|
+
|
|
1091
|
+
for user in self.get_users(
|
|
1092
|
+
project_name=project_name,
|
|
1093
|
+
usernames={username},
|
|
1094
|
+
fields=fields,
|
|
1095
|
+
):
|
|
1096
|
+
return user
|
|
1097
|
+
return None
|
|
1098
|
+
|
|
1063
1099
|
def get_user(self, username=None):
|
|
1100
|
+
"""Get user info using REST endpoit.
|
|
1101
|
+
|
|
1102
|
+
Args:
|
|
1103
|
+
username (Optional[str]): Username.
|
|
1104
|
+
|
|
1105
|
+
Returns:
|
|
1106
|
+
Union[dict[str, Any], None]: User info or None if user is not
|
|
1107
|
+
found.
|
|
1108
|
+
|
|
1109
|
+
"""
|
|
1064
1110
|
if username is None:
|
|
1065
1111
|
output = self._get_user_info()
|
|
1066
1112
|
if output is None:
|
|
@@ -1607,7 +1653,13 @@ class ServerAPI(object):
|
|
|
1607
1653
|
response = self.post("enroll", **kwargs)
|
|
1608
1654
|
if response.status_code == 204:
|
|
1609
1655
|
return None
|
|
1610
|
-
|
|
1656
|
+
|
|
1657
|
+
if response.status_code == 503:
|
|
1658
|
+
# Server is busy
|
|
1659
|
+
self.log.info("Server is busy. Can't enroll event now.")
|
|
1660
|
+
return None
|
|
1661
|
+
|
|
1662
|
+
if response.status_code >= 400:
|
|
1611
1663
|
self.log.error(response.text)
|
|
1612
1664
|
return None
|
|
1613
1665
|
|
|
@@ -1886,6 +1938,77 @@ class ServerAPI(object):
|
|
|
1886
1938
|
endpoint, stream, progress, request_type, **kwargs
|
|
1887
1939
|
)
|
|
1888
1940
|
|
|
1941
|
+
def upload_reviewable(
|
|
1942
|
+
self,
|
|
1943
|
+
project_name,
|
|
1944
|
+
version_id,
|
|
1945
|
+
filepath,
|
|
1946
|
+
label=None,
|
|
1947
|
+
content_type=None,
|
|
1948
|
+
filename=None,
|
|
1949
|
+
progress=None,
|
|
1950
|
+
headers=None,
|
|
1951
|
+
**kwargs
|
|
1952
|
+
):
|
|
1953
|
+
"""Upload reviewable file to server.
|
|
1954
|
+
|
|
1955
|
+
Args:
|
|
1956
|
+
project_name (str): Project name.
|
|
1957
|
+
version_id (str): Version id.
|
|
1958
|
+
filepath (str): Reviewable file path to upload.
|
|
1959
|
+
label (Optional[str]): Reviewable label. Filled automatically
|
|
1960
|
+
server side with filename.
|
|
1961
|
+
content_type (Optional[str]): MIME type of the file.
|
|
1962
|
+
filename (Optional[str]): User as original filename. Filename from
|
|
1963
|
+
'filepath' is used when not filled.
|
|
1964
|
+
progress (Optional[TransferProgress]): Progress.
|
|
1965
|
+
headers (Optional[Dict[str, Any]]): Headers.
|
|
1966
|
+
|
|
1967
|
+
Returns:
|
|
1968
|
+
RestApiResponse: Server response.
|
|
1969
|
+
|
|
1970
|
+
"""
|
|
1971
|
+
if not content_type:
|
|
1972
|
+
content_type = get_media_mime_type(filepath)
|
|
1973
|
+
|
|
1974
|
+
if not content_type:
|
|
1975
|
+
raise ValueError(
|
|
1976
|
+
f"Could not determine MIME type of file '{filepath}'"
|
|
1977
|
+
)
|
|
1978
|
+
|
|
1979
|
+
if headers is None:
|
|
1980
|
+
headers = self.get_headers(content_type)
|
|
1981
|
+
else:
|
|
1982
|
+
# Make sure content-type is filled with file content type
|
|
1983
|
+
content_type_key = next(
|
|
1984
|
+
(
|
|
1985
|
+
key
|
|
1986
|
+
for key in headers
|
|
1987
|
+
if key.lower() == "content-type"
|
|
1988
|
+
),
|
|
1989
|
+
"Content-Type"
|
|
1990
|
+
)
|
|
1991
|
+
headers[content_type_key] = content_type
|
|
1992
|
+
|
|
1993
|
+
# Fill original filename if not explicitly defined
|
|
1994
|
+
if not filename:
|
|
1995
|
+
filename = os.path.basename(filepath)
|
|
1996
|
+
headers["x-file-name"] = filename
|
|
1997
|
+
|
|
1998
|
+
query = f"?label={label}" if label else ""
|
|
1999
|
+
endpoint = (
|
|
2000
|
+
f"/projects/{project_name}"
|
|
2001
|
+
f"/versions/{version_id}/reviewables{query}"
|
|
2002
|
+
)
|
|
2003
|
+
return self.upload_file(
|
|
2004
|
+
endpoint,
|
|
2005
|
+
filepath,
|
|
2006
|
+
progress=progress,
|
|
2007
|
+
headers=headers,
|
|
2008
|
+
request_type=RequestTypes.post,
|
|
2009
|
+
**kwargs
|
|
2010
|
+
)
|
|
2011
|
+
|
|
1889
2012
|
def trigger_server_restart(self):
|
|
1890
2013
|
"""Trigger server restart.
|
|
1891
2014
|
|
|
@@ -6336,6 +6459,7 @@ class ServerAPI(object):
|
|
|
6336
6459
|
representation_ids,
|
|
6337
6460
|
project_fields=None,
|
|
6338
6461
|
folder_fields=None,
|
|
6462
|
+
task_fields=None,
|
|
6339
6463
|
product_fields=None,
|
|
6340
6464
|
version_fields=None,
|
|
6341
6465
|
representation_fields=None,
|
|
@@ -6353,6 +6477,7 @@ class ServerAPI(object):
|
|
|
6353
6477
|
representation_ids (Iterable[str]): Representation ids.
|
|
6354
6478
|
project_fields (Optional[Iterable[str]]): Project fields.
|
|
6355
6479
|
folder_fields (Optional[Iterable[str]]): Folder fields.
|
|
6480
|
+
task_fields (Optional[Iterable[str]]): Task fields.
|
|
6356
6481
|
product_fields (Optional[Iterable[str]]): Product fields.
|
|
6357
6482
|
version_fields (Optional[Iterable[str]]): Version fields.
|
|
6358
6483
|
representation_fields (Optional[Iterable[str]]): Representation
|
|
@@ -6383,7 +6508,7 @@ class ServerAPI(object):
|
|
|
6383
6508
|
repre_ids = set(representation_ids)
|
|
6384
6509
|
output = {
|
|
6385
6510
|
repre_id: RepresentationHierarchy(
|
|
6386
|
-
project, None, None, None, None
|
|
6511
|
+
project, None, None, None, None, None
|
|
6387
6512
|
)
|
|
6388
6513
|
for repre_id in representation_ids
|
|
6389
6514
|
}
|
|
@@ -6393,6 +6518,11 @@ class ServerAPI(object):
|
|
|
6393
6518
|
else:
|
|
6394
6519
|
folder_fields = set(folder_fields)
|
|
6395
6520
|
|
|
6521
|
+
if task_fields is None:
|
|
6522
|
+
task_fields = self.get_default_fields_for_type("task")
|
|
6523
|
+
else:
|
|
6524
|
+
task_fields = set(task_fields)
|
|
6525
|
+
|
|
6396
6526
|
if product_fields is None:
|
|
6397
6527
|
product_fields = self.get_default_fields_for_type("product")
|
|
6398
6528
|
else:
|
|
@@ -6414,6 +6544,7 @@ class ServerAPI(object):
|
|
|
6414
6544
|
|
|
6415
6545
|
query = representations_hierarchy_qraphql_query(
|
|
6416
6546
|
folder_fields,
|
|
6547
|
+
task_fields,
|
|
6417
6548
|
product_fields,
|
|
6418
6549
|
version_fields,
|
|
6419
6550
|
representation_fields,
|
|
@@ -6426,12 +6557,16 @@ class ServerAPI(object):
|
|
|
6426
6557
|
repre_id = repre["id"]
|
|
6427
6558
|
version = repre.pop("version", {})
|
|
6428
6559
|
product = version.pop("product", {})
|
|
6560
|
+
task = version.pop("task", None)
|
|
6429
6561
|
folder = product.pop("folder", {})
|
|
6430
6562
|
self._convert_entity_data(version)
|
|
6431
6563
|
self._convert_entity_data(product)
|
|
6432
6564
|
self._convert_entity_data(folder)
|
|
6565
|
+
if task:
|
|
6566
|
+
self._convert_entity_data(task)
|
|
6567
|
+
|
|
6433
6568
|
output[repre_id] = RepresentationHierarchy(
|
|
6434
|
-
project, folder, product, version, repre
|
|
6569
|
+
project, folder, task, product, version, repre
|
|
6435
6570
|
)
|
|
6436
6571
|
|
|
6437
6572
|
return output
|
|
@@ -6442,6 +6577,7 @@ class ServerAPI(object):
|
|
|
6442
6577
|
representation_id,
|
|
6443
6578
|
project_fields=None,
|
|
6444
6579
|
folder_fields=None,
|
|
6580
|
+
task_fields=None,
|
|
6445
6581
|
product_fields=None,
|
|
6446
6582
|
version_fields=None,
|
|
6447
6583
|
representation_fields=None,
|
|
@@ -6455,6 +6591,7 @@ class ServerAPI(object):
|
|
|
6455
6591
|
representation_id (str): Representation id.
|
|
6456
6592
|
project_fields (Optional[Iterable[str]]): Project fields.
|
|
6457
6593
|
folder_fields (Optional[Iterable[str]]): Folder fields.
|
|
6594
|
+
task_fields (Optional[Iterable[str]]): Task fields.
|
|
6458
6595
|
product_fields (Optional[Iterable[str]]): Product fields.
|
|
6459
6596
|
version_fields (Optional[Iterable[str]]): Version fields.
|
|
6460
6597
|
representation_fields (Optional[Iterable[str]]): Representation
|
|
@@ -6472,6 +6609,7 @@ class ServerAPI(object):
|
|
|
6472
6609
|
[representation_id],
|
|
6473
6610
|
project_fields=project_fields,
|
|
6474
6611
|
folder_fields=folder_fields,
|
|
6612
|
+
task_fields=task_fields,
|
|
6475
6613
|
product_fields=product_fields,
|
|
6476
6614
|
version_fields=version_fields,
|
|
6477
6615
|
representation_fields=representation_fields,
|
|
@@ -6509,6 +6647,7 @@ class ServerAPI(object):
|
|
|
6509
6647
|
representation_ids,
|
|
6510
6648
|
project_fields=project_fields,
|
|
6511
6649
|
folder_fields=folder_fields,
|
|
6650
|
+
task_fields=set(),
|
|
6512
6651
|
product_fields=product_fields,
|
|
6513
6652
|
version_fields=version_fields,
|
|
6514
6653
|
representation_fields={"id"},
|
|
@@ -8073,11 +8212,11 @@ class ServerAPI(object):
|
|
|
8073
8212
|
return op_results
|
|
8074
8213
|
|
|
8075
8214
|
def _convert_entity_data(self, entity):
|
|
8076
|
-
if not entity:
|
|
8215
|
+
if not entity or "data" not in entity:
|
|
8077
8216
|
return
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8217
|
+
|
|
8218
|
+
entity_data = entity["data"] or {}
|
|
8219
|
+
if isinstance(entity_data, str):
|
|
8220
|
+
entity_data = json.loads(entity_data)
|
|
8221
|
+
|
|
8222
|
+
entity["data"] = entity_data
|
|
@@ -6,6 +6,7 @@ import string
|
|
|
6
6
|
import platform
|
|
7
7
|
import collections
|
|
8
8
|
from urllib.parse import urlparse, urlencode
|
|
9
|
+
from typing import Optional
|
|
9
10
|
|
|
10
11
|
import requests
|
|
11
12
|
import unidecode
|
|
@@ -29,7 +30,14 @@ RepresentationParents = collections.namedtuple(
|
|
|
29
30
|
|
|
30
31
|
RepresentationHierarchy = collections.namedtuple(
|
|
31
32
|
"RepresentationHierarchy",
|
|
32
|
-
(
|
|
33
|
+
(
|
|
34
|
+
"project",
|
|
35
|
+
"folder",
|
|
36
|
+
"task",
|
|
37
|
+
"product",
|
|
38
|
+
"version",
|
|
39
|
+
"representation",
|
|
40
|
+
)
|
|
33
41
|
)
|
|
34
42
|
|
|
35
43
|
|
|
@@ -341,10 +349,8 @@ def logout_from_server(url, token, timeout=None):
|
|
|
341
349
|
)
|
|
342
350
|
|
|
343
351
|
|
|
344
|
-
def
|
|
345
|
-
"""
|
|
346
|
-
|
|
347
|
-
Token can be a user token or service api key.
|
|
352
|
+
def get_user_by_token(url, token, timeout=None):
|
|
353
|
+
"""Get user information by url and token.
|
|
348
354
|
|
|
349
355
|
Args:
|
|
350
356
|
url (str): Server url.
|
|
@@ -353,7 +359,7 @@ def is_token_valid(url, token, timeout=None):
|
|
|
353
359
|
'get_default_timeout' is used if not specified.
|
|
354
360
|
|
|
355
361
|
Returns:
|
|
356
|
-
|
|
362
|
+
Optional[Dict[str, Any]]: User information if url and token are valid.
|
|
357
363
|
|
|
358
364
|
"""
|
|
359
365
|
if timeout is None:
|
|
@@ -374,7 +380,27 @@ def is_token_valid(url, token, timeout=None):
|
|
|
374
380
|
timeout=timeout,
|
|
375
381
|
)
|
|
376
382
|
if response.status_code == 200:
|
|
377
|
-
return
|
|
383
|
+
return response.json()
|
|
384
|
+
return None
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def is_token_valid(url, token, timeout=None):
|
|
388
|
+
"""Check if token is valid.
|
|
389
|
+
|
|
390
|
+
Token can be a user token or service api key.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
url (str): Server url.
|
|
394
|
+
token (str): User's token.
|
|
395
|
+
timeout (Optional[float]): Timeout for request. Value from
|
|
396
|
+
'get_default_timeout' is used if not specified.
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
bool: True if token is valid.
|
|
400
|
+
|
|
401
|
+
"""
|
|
402
|
+
if get_user_by_token(url, token, timeout=timeout):
|
|
403
|
+
return True
|
|
378
404
|
return False
|
|
379
405
|
|
|
380
406
|
|
|
@@ -697,3 +723,116 @@ def create_dependency_package_basename(platform_name=None):
|
|
|
697
723
|
now_date = datetime.datetime.now()
|
|
698
724
|
time_stamp = now_date.strftime("%y%m%d%H%M")
|
|
699
725
|
return "ayon_{}_{}".format(time_stamp, platform_name)
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
def _get_media_mime_type_from_ftyp(content):
|
|
730
|
+
if content[8:10] == b"qt" or content[8:12] == b"MSNV":
|
|
731
|
+
return "video/quicktime"
|
|
732
|
+
|
|
733
|
+
if content[8:12] in (b"3g2a", b"3g2b", b"3g2c", b"KDDI"):
|
|
734
|
+
return "video/3gpp2"
|
|
735
|
+
|
|
736
|
+
if content[8:12] in (
|
|
737
|
+
b"isom", b"iso2", b"avc1", b"F4V", b"F4P", b"F4A", b"F4B", b"mmp4",
|
|
738
|
+
# These might be "video/mp4v"
|
|
739
|
+
b"mp41", b"mp42",
|
|
740
|
+
# Nero
|
|
741
|
+
b"NDSC", b"NDSH", b"NDSM", b"NDSP", b"NDSS", b"NDXC", b"NDXH",
|
|
742
|
+
b"NDXM", b"NDXP", b"NDXS",
|
|
743
|
+
):
|
|
744
|
+
return "video/mp4"
|
|
745
|
+
|
|
746
|
+
if content[8:12] in (
|
|
747
|
+
b"3ge6", b"3ge7", b"3gg6",
|
|
748
|
+
b"3gp1", b"3gp2", b"3gp3", b"3gp4", b"3gp5", b"3gp6", b"3gs7",
|
|
749
|
+
):
|
|
750
|
+
return "video/3gpp"
|
|
751
|
+
|
|
752
|
+
if content[8:11] == b"JP2":
|
|
753
|
+
return "image/jp2"
|
|
754
|
+
|
|
755
|
+
if content[8:11] == b"jpm":
|
|
756
|
+
return "image/jpm"
|
|
757
|
+
|
|
758
|
+
if content[8:11] == b"jpx":
|
|
759
|
+
return "image/jpx"
|
|
760
|
+
|
|
761
|
+
if content[8:12] in (b"M4V\x20", b"M4VH", b"M4VP"):
|
|
762
|
+
return "video/x-m4v"
|
|
763
|
+
|
|
764
|
+
if content[8:12] in (b"mj2s", b"mjp2"):
|
|
765
|
+
return "video/mj2"
|
|
766
|
+
return None
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
def get_media_mime_type_for_content(content: bytes) -> Optional[str]:
|
|
770
|
+
content_len = len(content)
|
|
771
|
+
# Pre-validation (largest definition check)
|
|
772
|
+
# - hopefully there cannot be media defined in less than 12 bytes
|
|
773
|
+
if content_len < 12:
|
|
774
|
+
return None
|
|
775
|
+
|
|
776
|
+
# FTYP
|
|
777
|
+
if content[4:8] == b"ftyp":
|
|
778
|
+
return _get_media_mime_type_from_ftyp(content)
|
|
779
|
+
|
|
780
|
+
# BMP
|
|
781
|
+
if content[0:2] == b"BM":
|
|
782
|
+
return "image/bmp"
|
|
783
|
+
|
|
784
|
+
# Tiff
|
|
785
|
+
if content[0:2] in (b"MM", b"II"):
|
|
786
|
+
return "tiff"
|
|
787
|
+
|
|
788
|
+
# PNG
|
|
789
|
+
if content[0:4] == b"\211PNG":
|
|
790
|
+
return "image/png"
|
|
791
|
+
|
|
792
|
+
# SVG
|
|
793
|
+
if b'xmlns="http://www.w3.org/2000/svg"' in content:
|
|
794
|
+
return "image/svg+xml"
|
|
795
|
+
|
|
796
|
+
# JPEG, JFIF or Exif
|
|
797
|
+
if (
|
|
798
|
+
content[0:4] == b"\xff\xd8\xff\xdb"
|
|
799
|
+
or content[6:10] in (b"JFIF", b"Exif")
|
|
800
|
+
):
|
|
801
|
+
return "image/jpeg"
|
|
802
|
+
|
|
803
|
+
# Webp
|
|
804
|
+
if content[0:4] == b"RIFF" and content[8:12] == b"WEBP":
|
|
805
|
+
return "image/webp"
|
|
806
|
+
|
|
807
|
+
# Gif
|
|
808
|
+
if content[0:6] in (b"GIF87a", b"GIF89a"):
|
|
809
|
+
return "gif"
|
|
810
|
+
|
|
811
|
+
# Adobe PhotoShop file (8B > Adobe, PS > PhotoShop)
|
|
812
|
+
if content[0:4] == b"8BPS":
|
|
813
|
+
return "image/vnd.adobe.photoshop"
|
|
814
|
+
|
|
815
|
+
# Windows ICO > this might be wild guess as multiple files can start
|
|
816
|
+
# with this header
|
|
817
|
+
if content[0:4] == b"\x00\x00\x01\x00":
|
|
818
|
+
return "image/x-icon"
|
|
819
|
+
return None
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def get_media_mime_type(filepath: str) -> Optional[str]:
|
|
823
|
+
"""Determine Mime-Type of a file.
|
|
824
|
+
|
|
825
|
+
Args:
|
|
826
|
+
filepath (str): Path to file.
|
|
827
|
+
|
|
828
|
+
Returns:
|
|
829
|
+
Optional[str]: Mime type or None if is unknown mime type.
|
|
830
|
+
|
|
831
|
+
"""
|
|
832
|
+
if not filepath or not os.path.exists(filepath):
|
|
833
|
+
return None
|
|
834
|
+
|
|
835
|
+
with open(filepath, "rb") as stream:
|
|
836
|
+
content = stream.read()
|
|
837
|
+
|
|
838
|
+
return get_media_mime_type_for_content(content)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Package declaring Python API for AYON server."""
|
|
2
|
-
__version__ = "1.0.
|
|
2
|
+
__version__ = "1.0.8"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ayon-python-api"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.8"
|
|
4
4
|
description = "AYON Python API"
|
|
5
5
|
license = {file = "LICENSE"}
|
|
6
6
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
@@ -29,7 +29,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
29
29
|
|
|
30
30
|
[tool.poetry]
|
|
31
31
|
name = "ayon-python-api"
|
|
32
|
-
version = "1.0.
|
|
32
|
+
version = "1.0.8"
|
|
33
33
|
description = "AYON Python API"
|
|
34
34
|
authors = [
|
|
35
35
|
"ynput.io <info@ynput.io>"
|
|
File without changes
|
|
File without changes
|
|
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.6 → ayon-python-api-1.0.8}/ayon_python_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|