Ayon-Python-Api 0.1.4__tar.gz → 0.1.7__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-0.1.4/ayon_python_api.egg-info → ayon-python-api-0.1.7}/PKG-INFO +1 -1
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/__init__.py +83 -3
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/server.py +427 -18
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/server_api.py +135 -10
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/utils.py +99 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/version.py +1 -1
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7/ayon_python_api.egg-info}/PKG-INFO +1 -1
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/pyproject.toml +1 -1
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/setup.py +1 -1
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/LICENSE +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/README.md +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/constants.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/entity_hub.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/events.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/exceptions.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/graphql.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/graphql_queries.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/operations.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/thumbnails.py +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/SOURCES.txt +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/dependency_links.txt +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/requires.txt +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/top_level.txt +0 -0
- {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/setup.cfg +0 -0
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from .utils import (
|
|
2
|
+
TransferProgress,
|
|
3
|
+
)
|
|
1
4
|
from .server import (
|
|
2
5
|
ServerAPIBase,
|
|
3
6
|
)
|
|
@@ -7,12 +10,51 @@ from .server_api import (
|
|
|
7
10
|
|
|
8
11
|
get_server_api_connection,
|
|
9
12
|
|
|
13
|
+
get_base_url,
|
|
14
|
+
get_rest_url,
|
|
15
|
+
|
|
16
|
+
raw_get,
|
|
17
|
+
raw_post,
|
|
18
|
+
raw_put,
|
|
19
|
+
raw_patch,
|
|
20
|
+
raw_delete,
|
|
21
|
+
|
|
10
22
|
get,
|
|
11
23
|
post,
|
|
12
24
|
put,
|
|
13
25
|
patch,
|
|
14
26
|
delete,
|
|
15
27
|
|
|
28
|
+
download_file,
|
|
29
|
+
upload_file,
|
|
30
|
+
|
|
31
|
+
query_graphql,
|
|
32
|
+
|
|
33
|
+
get_addons_info,
|
|
34
|
+
download_addon_private_file,
|
|
35
|
+
|
|
36
|
+
get_dependencies_info,
|
|
37
|
+
update_dependency_info,
|
|
38
|
+
|
|
39
|
+
download_dependency_package,
|
|
40
|
+
upload_dependency_package,
|
|
41
|
+
delete_dependency_package,
|
|
42
|
+
|
|
43
|
+
get_full_production_settings,
|
|
44
|
+
get_production_settings,
|
|
45
|
+
get_full_project_settings,
|
|
46
|
+
get_project_settings,
|
|
47
|
+
get_addon_settings,
|
|
48
|
+
|
|
49
|
+
get_user,
|
|
50
|
+
get_users,
|
|
51
|
+
|
|
52
|
+
get_attributes_for_type,
|
|
53
|
+
get_default_fields_for_type,
|
|
54
|
+
|
|
55
|
+
get_project_anatomy_preset,
|
|
56
|
+
get_project_anatomy_presets,
|
|
57
|
+
|
|
16
58
|
get_projects,
|
|
17
59
|
get_project,
|
|
18
60
|
create_project,
|
|
@@ -47,9 +89,6 @@ from .server_api import (
|
|
|
47
89
|
get_representations_parents,
|
|
48
90
|
get_representation_parents,
|
|
49
91
|
|
|
50
|
-
get_project_settings,
|
|
51
|
-
get_addon_settings,
|
|
52
|
-
|
|
53
92
|
create_thumbnail,
|
|
54
93
|
get_thumbnail,
|
|
55
94
|
get_folder_thumbnail,
|
|
@@ -59,19 +98,59 @@ from .server_api import (
|
|
|
59
98
|
|
|
60
99
|
|
|
61
100
|
__all__ = (
|
|
101
|
+
"TransferProgress",
|
|
102
|
+
|
|
62
103
|
"ServerAPIBase",
|
|
63
104
|
|
|
64
105
|
"ServerAPI",
|
|
106
|
+
|
|
65
107
|
"get_server_api_connection",
|
|
108
|
+
|
|
109
|
+
"get_base_url",
|
|
110
|
+
"get_rest_url",
|
|
111
|
+
|
|
112
|
+
"raw_get",
|
|
113
|
+
"raw_post",
|
|
114
|
+
"raw_put",
|
|
115
|
+
"raw_patch",
|
|
116
|
+
"raw_delete",
|
|
117
|
+
|
|
66
118
|
"get",
|
|
67
119
|
"post",
|
|
68
120
|
"put",
|
|
69
121
|
"patch",
|
|
70
122
|
"delete",
|
|
71
123
|
|
|
124
|
+
"download_file",
|
|
125
|
+
"upload_file",
|
|
126
|
+
|
|
127
|
+
"query_graphql",
|
|
128
|
+
|
|
129
|
+
"get_addons_info",
|
|
130
|
+
"download_addon_private_file",
|
|
131
|
+
|
|
132
|
+
"get_dependencies_info",
|
|
133
|
+
"update_dependency_info",
|
|
134
|
+
|
|
135
|
+
"download_dependency_package",
|
|
136
|
+
"upload_dependency_package",
|
|
137
|
+
"delete_dependency_package",
|
|
138
|
+
|
|
139
|
+
"get_full_production_settings",
|
|
140
|
+
"get_production_settings",
|
|
141
|
+
"get_full_project_settings",
|
|
72
142
|
"get_project_settings",
|
|
73
143
|
"get_addon_settings",
|
|
74
144
|
|
|
145
|
+
"get_user",
|
|
146
|
+
"get_users",
|
|
147
|
+
|
|
148
|
+
"get_attributes_for_type",
|
|
149
|
+
"get_default_fields_for_type",
|
|
150
|
+
|
|
151
|
+
"get_project_anatomy_preset",
|
|
152
|
+
"get_project_anatomy_presets",
|
|
153
|
+
|
|
75
154
|
"get_projects",
|
|
76
155
|
"get_project",
|
|
77
156
|
"create_project",
|
|
@@ -89,6 +168,7 @@ __all__ = (
|
|
|
89
168
|
"get_subset_by_name",
|
|
90
169
|
"get_subsets",
|
|
91
170
|
"get_subset_families",
|
|
171
|
+
|
|
92
172
|
"get_version_by_id",
|
|
93
173
|
"get_version_by_name",
|
|
94
174
|
"version_is_latest",
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
|
+
import io
|
|
3
4
|
import json
|
|
4
5
|
import logging
|
|
5
6
|
import collections
|
|
7
|
+
import platform
|
|
6
8
|
import copy
|
|
7
9
|
from http import HTTPStatus
|
|
8
10
|
|
|
@@ -36,12 +38,14 @@ from .exceptions import (
|
|
|
36
38
|
UnauthorizedError,
|
|
37
39
|
AuthenticationError,
|
|
38
40
|
ServerNotReached,
|
|
41
|
+
ServerError,
|
|
39
42
|
)
|
|
40
43
|
from .utils import (
|
|
41
44
|
logout_from_server,
|
|
42
45
|
create_entity_id,
|
|
43
46
|
entity_data_json_default,
|
|
44
|
-
failed_json_default
|
|
47
|
+
failed_json_default,
|
|
48
|
+
TransferProgress,
|
|
45
49
|
)
|
|
46
50
|
|
|
47
51
|
JSONDecodeError = getattr(json, "JSONDecodeError", ValueError)
|
|
@@ -151,10 +155,21 @@ class ServerAPIBase(object):
|
|
|
151
155
|
Login cause that a session is used
|
|
152
156
|
|
|
153
157
|
Args:
|
|
154
|
-
base_url(str): Example: http://localhost:5000
|
|
158
|
+
base_url (str): Example: http://localhost:5000
|
|
159
|
+
token (str): Access token (api key) to server.
|
|
160
|
+
site_id (str): Unique name of site. Should be the same when
|
|
161
|
+
connection is created from the same machine under same user.
|
|
162
|
+
client_version (str): Version of client application (used in
|
|
163
|
+
desktop client application).
|
|
155
164
|
"""
|
|
156
165
|
|
|
157
|
-
def __init__(
|
|
166
|
+
def __init__(
|
|
167
|
+
self,
|
|
168
|
+
base_url,
|
|
169
|
+
token=None,
|
|
170
|
+
site_id=None,
|
|
171
|
+
client_version=None
|
|
172
|
+
):
|
|
158
173
|
if not base_url:
|
|
159
174
|
raise ValueError("Invalid server URL {}".format(str(base_url)))
|
|
160
175
|
|
|
@@ -164,6 +179,8 @@ class ServerAPIBase(object):
|
|
|
164
179
|
self._graphl_url = "{}/graphql".format(base_url)
|
|
165
180
|
self._log = None
|
|
166
181
|
self._access_token = token
|
|
182
|
+
self._site_id = site_id
|
|
183
|
+
self._client_version = client_version
|
|
167
184
|
self._access_token_is_service = None
|
|
168
185
|
self._token_is_valid = None
|
|
169
186
|
self._server_available = None
|
|
@@ -185,10 +202,33 @@ class ServerAPIBase(object):
|
|
|
185
202
|
|
|
186
203
|
self._thumbnail_cache = ThumbnailCache(True)
|
|
187
204
|
|
|
205
|
+
def get_base_url(self):
|
|
206
|
+
return self._base_url
|
|
207
|
+
|
|
208
|
+
def get_rest_url(self):
|
|
209
|
+
return self._rest_url
|
|
210
|
+
|
|
211
|
+
base_url = property(get_base_url)
|
|
212
|
+
rest_url = property(get_rest_url)
|
|
213
|
+
|
|
188
214
|
@property
|
|
189
215
|
def access_token(self):
|
|
190
216
|
return self._access_token
|
|
191
217
|
|
|
218
|
+
def get_site_id(self):
|
|
219
|
+
return self._site_id
|
|
220
|
+
|
|
221
|
+
def set_site_id(self, site_id):
|
|
222
|
+
if self._site_id == site_id:
|
|
223
|
+
return
|
|
224
|
+
self._site_id = site_id
|
|
225
|
+
# Recreate session on machine id change
|
|
226
|
+
if self._session is not None:
|
|
227
|
+
self.close_session()
|
|
228
|
+
self.create_session()
|
|
229
|
+
|
|
230
|
+
site_id = property(get_site_id, set_site_id)
|
|
231
|
+
|
|
192
232
|
@property
|
|
193
233
|
def is_server_available(self):
|
|
194
234
|
if self._server_available is None:
|
|
@@ -213,7 +253,11 @@ class ServerAPIBase(object):
|
|
|
213
253
|
|
|
214
254
|
def validate_token(self):
|
|
215
255
|
try:
|
|
216
|
-
|
|
256
|
+
# TODO add other possible validations
|
|
257
|
+
# - existence of 'user' key in info
|
|
258
|
+
# - validate that 'site_id' is in 'sites' in info
|
|
259
|
+
self.get_info()
|
|
260
|
+
self.get_user()
|
|
217
261
|
self._token_is_valid = True
|
|
218
262
|
|
|
219
263
|
except UnauthorizedError:
|
|
@@ -223,7 +267,7 @@ class ServerAPIBase(object):
|
|
|
223
267
|
def set_token(self, token):
|
|
224
268
|
self.reset_token()
|
|
225
269
|
self._access_token = token
|
|
226
|
-
self.
|
|
270
|
+
self.get_user()
|
|
227
271
|
|
|
228
272
|
def reset_token(self):
|
|
229
273
|
self._access_token = None
|
|
@@ -258,6 +302,23 @@ class ServerAPIBase(object):
|
|
|
258
302
|
self._session_functions_mapping = {}
|
|
259
303
|
session.close()
|
|
260
304
|
|
|
305
|
+
def get_info(self):
|
|
306
|
+
"""Get information about current used api key.
|
|
307
|
+
|
|
308
|
+
By default, the 'info' contains only 'uptime' and 'version'. With
|
|
309
|
+
logged user info also contains information about user and machines on
|
|
310
|
+
which was logged in.
|
|
311
|
+
|
|
312
|
+
Todos:
|
|
313
|
+
Use this method for validation of token instead of 'get_user'.
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Dict[str, Any]: Information from server.
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
response = self.get("info")
|
|
320
|
+
return response.data
|
|
321
|
+
|
|
261
322
|
def _get_user_info(self):
|
|
262
323
|
if self._access_token is None:
|
|
263
324
|
return None
|
|
@@ -279,11 +340,23 @@ class ServerAPIBase(object):
|
|
|
279
340
|
self._access_token_is_service = None
|
|
280
341
|
return None
|
|
281
342
|
|
|
282
|
-
def
|
|
283
|
-
|
|
284
|
-
|
|
343
|
+
def get_users(self):
|
|
344
|
+
# TODO how to find out if user have permission?
|
|
345
|
+
users = self.get("users")
|
|
346
|
+
return users.data
|
|
347
|
+
|
|
348
|
+
def get_user(self, username=None):
|
|
349
|
+
output = None
|
|
350
|
+
if username is None:
|
|
351
|
+
output = self._get_user_info()
|
|
352
|
+
else:
|
|
353
|
+
response = self.get("users/{}".format(username))
|
|
354
|
+
if response.status == 200:
|
|
355
|
+
output = response.data
|
|
356
|
+
|
|
357
|
+
if output is None:
|
|
285
358
|
raise UnauthorizedError("User is not authorized.")
|
|
286
|
-
return
|
|
359
|
+
return output
|
|
287
360
|
|
|
288
361
|
@property
|
|
289
362
|
def log(self):
|
|
@@ -294,7 +367,18 @@ class ServerAPIBase(object):
|
|
|
294
367
|
def get_headers(self, content_type=None):
|
|
295
368
|
if content_type is None:
|
|
296
369
|
content_type = "application/json"
|
|
297
|
-
|
|
370
|
+
|
|
371
|
+
headers = {
|
|
372
|
+
"Content-Type": content_type,
|
|
373
|
+
"x-ayon-platform": platform.system().lower(),
|
|
374
|
+
"x-ayon-hostname": platform.node(),
|
|
375
|
+
}
|
|
376
|
+
if self._site_id is not None:
|
|
377
|
+
headers["x-ayon-site-id"] = self._site_id
|
|
378
|
+
|
|
379
|
+
if self._client_version is not None:
|
|
380
|
+
headers["x-ayon-version"] = self._client_version
|
|
381
|
+
|
|
298
382
|
if self._access_token:
|
|
299
383
|
if self._access_token_is_service:
|
|
300
384
|
headers["X-Api-Key"] = self._access_token
|
|
@@ -306,7 +390,7 @@ class ServerAPIBase(object):
|
|
|
306
390
|
def login(self, username, password):
|
|
307
391
|
if self.has_valid_token:
|
|
308
392
|
try:
|
|
309
|
-
user_info = self.
|
|
393
|
+
user_info = self.get_user()
|
|
310
394
|
except UnauthorizedError:
|
|
311
395
|
user_info = {}
|
|
312
396
|
|
|
@@ -471,6 +555,126 @@ class ServerAPIBase(object):
|
|
|
471
555
|
def delete(self, entrypoint, **kwargs):
|
|
472
556
|
return self.raw_delete(entrypoint, params=kwargs)
|
|
473
557
|
|
|
558
|
+
def _download_file(self, url, filepath, chunk_size, progress):
|
|
559
|
+
dst_directory = os.path.dirname(filepath)
|
|
560
|
+
if not os.path.exists(dst_directory):
|
|
561
|
+
os.makedirs(dst_directory)
|
|
562
|
+
|
|
563
|
+
kwargs = {"stream": True}
|
|
564
|
+
if self._session is None:
|
|
565
|
+
kwargs["headers"] = self.get_headers()
|
|
566
|
+
get_func = self._base_functions_mapping[RequestTypes.get]
|
|
567
|
+
else:
|
|
568
|
+
get_func = self._session_functions_mapping[RequestTypes.get]
|
|
569
|
+
|
|
570
|
+
with open(filepath, "wb") as f_stream:
|
|
571
|
+
with get_func(url, **kwargs) as response:
|
|
572
|
+
response.raise_for_status()
|
|
573
|
+
progress.set_content_size(response.headers["Content-length"])
|
|
574
|
+
for chunk in response.iter_content(chunk_size=chunk_size):
|
|
575
|
+
f_stream.write(chunk)
|
|
576
|
+
progress.add_downloaded_chunk(len(chunk))
|
|
577
|
+
|
|
578
|
+
def download_file(self, endpoint, filepath, chunk_size=None, progress=None):
|
|
579
|
+
"""Download file from AYON server.
|
|
580
|
+
|
|
581
|
+
Endpoint can be full url (must start with 'base_url' of api object).
|
|
582
|
+
|
|
583
|
+
Progress object can be used to track download. Can be used when
|
|
584
|
+
download happens in thread and other thread want to catch changes over
|
|
585
|
+
time.
|
|
586
|
+
|
|
587
|
+
Args:
|
|
588
|
+
endpoint (str): Endpoint or URL to file that should be downloaded.
|
|
589
|
+
filepath (str): Path where file will be downloaded.
|
|
590
|
+
chunk_size (int): Size of chunks that are received in single loop.
|
|
591
|
+
progress (TransferProgress): Object that gives ability to track
|
|
592
|
+
download progress.
|
|
593
|
+
"""
|
|
594
|
+
|
|
595
|
+
if not chunk_size:
|
|
596
|
+
# 1 MB chunk by default
|
|
597
|
+
chunk_size = 1024 * 1024
|
|
598
|
+
|
|
599
|
+
if endpoint.startswith(self._base_url):
|
|
600
|
+
url = endpoint
|
|
601
|
+
else:
|
|
602
|
+
endpoint = endpoint.lstrip("/").rstrip("/")
|
|
603
|
+
url = "{}/{}".format(self._rest_url, endpoint)
|
|
604
|
+
|
|
605
|
+
# Create dummy object so the function does not have to check
|
|
606
|
+
# 'progress' variable everywhere
|
|
607
|
+
if progress is None:
|
|
608
|
+
progress = TransferProgress()
|
|
609
|
+
|
|
610
|
+
progress.set_source_url(url)
|
|
611
|
+
progress.set_destination_url(filepath)
|
|
612
|
+
progress.set_started()
|
|
613
|
+
try:
|
|
614
|
+
self._download_file(url, filepath, chunk_size, progress)
|
|
615
|
+
|
|
616
|
+
except Exception as exc:
|
|
617
|
+
progress.set_failed(str(exc))
|
|
618
|
+
raise
|
|
619
|
+
|
|
620
|
+
finally:
|
|
621
|
+
progress.set_done()
|
|
622
|
+
|
|
623
|
+
def _upload_file(self, url, filepath, progress):
|
|
624
|
+
kwargs = {}
|
|
625
|
+
if self._session is None:
|
|
626
|
+
kwargs["headers"] = self.get_headers()
|
|
627
|
+
post_func = self._base_functions_mapping[RequestTypes.post]
|
|
628
|
+
else:
|
|
629
|
+
post_func = self._session_functions_mapping[RequestTypes.post]
|
|
630
|
+
|
|
631
|
+
with open(filepath, "rb") as stream:
|
|
632
|
+
stream.seek(0, io.SEEK_END)
|
|
633
|
+
size = stream.tell()
|
|
634
|
+
stream.seek(0)
|
|
635
|
+
progress.set_content_size(size)
|
|
636
|
+
response = post_func(url, data=stream, **kwargs)
|
|
637
|
+
response.raise_for_status()
|
|
638
|
+
progress.set_downloaded_size(size)
|
|
639
|
+
|
|
640
|
+
def upload_file(self, endpoint, filepath, progress=None):
|
|
641
|
+
"""Upload file to server.
|
|
642
|
+
|
|
643
|
+
Todos:
|
|
644
|
+
Uploading with more detailed progress.
|
|
645
|
+
|
|
646
|
+
Args:
|
|
647
|
+
endpoint (str): Endpoint or url where file will be uploaded.
|
|
648
|
+
filepath (str): Source filepath.
|
|
649
|
+
progress (TransferProgress): Object that gives ability to track
|
|
650
|
+
upload progress.
|
|
651
|
+
"""
|
|
652
|
+
|
|
653
|
+
if endpoint.startswith(self._base_url):
|
|
654
|
+
url = endpoint
|
|
655
|
+
else:
|
|
656
|
+
endpoint = endpoint.lstrip("/").rstrip("/")
|
|
657
|
+
url = "{}/{}".format(self._rest_url, endpoint)
|
|
658
|
+
|
|
659
|
+
# Create dummy object so the function does not have to check
|
|
660
|
+
# 'progress' variable everywhere
|
|
661
|
+
if progress is None:
|
|
662
|
+
progress = TransferProgress()
|
|
663
|
+
|
|
664
|
+
progress.set_source_url(filepath)
|
|
665
|
+
progress.set_destination_url(url)
|
|
666
|
+
progress.set_started()
|
|
667
|
+
|
|
668
|
+
try:
|
|
669
|
+
self._upload_file(url, filepath, progress)
|
|
670
|
+
|
|
671
|
+
except Exception as exc:
|
|
672
|
+
progress.set_failed(str(exc))
|
|
673
|
+
raise
|
|
674
|
+
|
|
675
|
+
finally:
|
|
676
|
+
progress.set_done()
|
|
677
|
+
|
|
474
678
|
def trigger_server_restart(self):
|
|
475
679
|
result = self.post("system/restart")
|
|
476
680
|
if result.status_code != 204:
|
|
@@ -673,6 +877,191 @@ class ServerAPIBase(object):
|
|
|
673
877
|
}
|
|
674
878
|
)
|
|
675
879
|
|
|
880
|
+
def get_addons_info(self, details=True):
|
|
881
|
+
"""Get information about addons available on server.
|
|
882
|
+
|
|
883
|
+
Args:
|
|
884
|
+
details (bool): Detailed data with information how to get client
|
|
885
|
+
code.
|
|
886
|
+
"""
|
|
887
|
+
|
|
888
|
+
endpoint = "addons"
|
|
889
|
+
if details:
|
|
890
|
+
endpoint += "?details=1"
|
|
891
|
+
response = self.get(endpoint)
|
|
892
|
+
if response.status != 200:
|
|
893
|
+
raise ServerError(response.text)
|
|
894
|
+
return response.data
|
|
895
|
+
|
|
896
|
+
def download_addon_private_file(
|
|
897
|
+
self,
|
|
898
|
+
addon_name,
|
|
899
|
+
addon_version,
|
|
900
|
+
filename,
|
|
901
|
+
destination_dir,
|
|
902
|
+
destination_filename=None,
|
|
903
|
+
chunk_size=None,
|
|
904
|
+
progress=None,
|
|
905
|
+
):
|
|
906
|
+
"""Download a file from addon private files.
|
|
907
|
+
|
|
908
|
+
This method requires to have authorized token available. Private files
|
|
909
|
+
are not under '/api' restpoint.
|
|
910
|
+
|
|
911
|
+
Args:
|
|
912
|
+
addon_name (str): Addon name.
|
|
913
|
+
addon_version (str): Addon version.
|
|
914
|
+
filename (str): Filename in private folder on server.
|
|
915
|
+
destination_dir (str): Where the file should be downloaded.
|
|
916
|
+
destination_filename (str): Name of destination filename. Source
|
|
917
|
+
filename is used if not passed.
|
|
918
|
+
chunk_size (int): Download chunk size.
|
|
919
|
+
progress (TransferProgress): Object that gives ability to track
|
|
920
|
+
download progress.
|
|
921
|
+
|
|
922
|
+
Returns:
|
|
923
|
+
str: Filepath to downloaded file.
|
|
924
|
+
"""
|
|
925
|
+
|
|
926
|
+
if not destination_filename:
|
|
927
|
+
destination_filename = filename
|
|
928
|
+
dst_filepath = os.path.join(destination_dir, destination_filename)
|
|
929
|
+
# Filename can contain "subfolders"
|
|
930
|
+
dst_dirpath = os.path.dirname(dst_filepath)
|
|
931
|
+
if not os.path.exists(dst_dirpath):
|
|
932
|
+
os.makedirs(dst_dirpath)
|
|
933
|
+
|
|
934
|
+
url = "{}/addons/{}/{}/private/{}".format(
|
|
935
|
+
self._base_url,
|
|
936
|
+
addon_name,
|
|
937
|
+
addon_version,
|
|
938
|
+
filename
|
|
939
|
+
)
|
|
940
|
+
self.download_file(
|
|
941
|
+
url, dst_filepath, chunk_size=chunk_size, progress=progress
|
|
942
|
+
)
|
|
943
|
+
return dst_filepath
|
|
944
|
+
|
|
945
|
+
def get_dependencies_info(self):
|
|
946
|
+
result = self.get("dependencies")
|
|
947
|
+
return result.data
|
|
948
|
+
|
|
949
|
+
def update_dependency_info(
|
|
950
|
+
self,
|
|
951
|
+
name,
|
|
952
|
+
platform_name,
|
|
953
|
+
size,
|
|
954
|
+
checksum,
|
|
955
|
+
checksum_algorithm=None,
|
|
956
|
+
supported_addons=None,
|
|
957
|
+
python_modules=None,
|
|
958
|
+
sources=None
|
|
959
|
+
):
|
|
960
|
+
"""Update or create dependency package infor by it's identifiers.
|
|
961
|
+
|
|
962
|
+
The endpoint can be used to create or update dependency package.
|
|
963
|
+
|
|
964
|
+
Args:
|
|
965
|
+
name (str): Name of dependency package.
|
|
966
|
+
platform_name (Literal["windows", "linux", "darwin"]): Platform for
|
|
967
|
+
which is dependency package targeted.
|
|
968
|
+
size (int): Size of dependency package in bytes.
|
|
969
|
+
checksum (str): Checksum of archive file where dependecies are.
|
|
970
|
+
checksum_algorithm (str): Algorithm used to calculate checksum.
|
|
971
|
+
By default, is used 'md5' (defined by server).
|
|
972
|
+
supported_addons (Dict[str, str]): Name of addons for which was the
|
|
973
|
+
package created ('{"<addon name>": "<addon version>", ...}').
|
|
974
|
+
python_modules (Dict[str, str]): Python modules in dependencies
|
|
975
|
+
package ('{"<module name>": "<module version>", ...}').
|
|
976
|
+
sources (List[Dict[str, Any]]): Information about sources where
|
|
977
|
+
dependency package is available.
|
|
978
|
+
"""
|
|
979
|
+
|
|
980
|
+
kwargs = {
|
|
981
|
+
key: value
|
|
982
|
+
for key, value in (
|
|
983
|
+
("checksumAlgorithm", checksum_algorithm),
|
|
984
|
+
("supportedAddons", supported_addons),
|
|
985
|
+
("pythonModules", python_modules),
|
|
986
|
+
("sources", sources),
|
|
987
|
+
)
|
|
988
|
+
if value
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
response = self.put(
|
|
992
|
+
"dependencies",
|
|
993
|
+
name=name,
|
|
994
|
+
platform=platform_name,
|
|
995
|
+
size=size,
|
|
996
|
+
checksum=checksum,
|
|
997
|
+
**kwargs
|
|
998
|
+
)
|
|
999
|
+
if response.status not in (200, 201):
|
|
1000
|
+
raise ServerError("Failed to create/update dependency")
|
|
1001
|
+
return response.data
|
|
1002
|
+
|
|
1003
|
+
def download_dependency_package(
|
|
1004
|
+
self,
|
|
1005
|
+
package_name,
|
|
1006
|
+
dst_directory,
|
|
1007
|
+
filename,
|
|
1008
|
+
platform_name=None,
|
|
1009
|
+
chunk_size=None,
|
|
1010
|
+
progress=None,
|
|
1011
|
+
):
|
|
1012
|
+
"""Download dependency package from server.
|
|
1013
|
+
|
|
1014
|
+
This method requires to have authorized token available. The package is
|
|
1015
|
+
only downloaded.
|
|
1016
|
+
|
|
1017
|
+
Args:
|
|
1018
|
+
package_name (str): Name of package to download.
|
|
1019
|
+
dst_directory (str): Where the file should be downloaded.
|
|
1020
|
+
filename (str): Name of destination filename.
|
|
1021
|
+
platform_name (str): Name of platform for which the dependency
|
|
1022
|
+
package is targetter. Default value is current platform.
|
|
1023
|
+
chunk_size (int): Download chunk size.
|
|
1024
|
+
progress (TransferProgress): Object that gives ability to track
|
|
1025
|
+
download progress.
|
|
1026
|
+
|
|
1027
|
+
Returns:
|
|
1028
|
+
str: Filepath to downloaded file.
|
|
1029
|
+
"""
|
|
1030
|
+
if platform_name is None:
|
|
1031
|
+
platform_name = platform.system().lower()
|
|
1032
|
+
|
|
1033
|
+
package_filepath = os.path.join(dst_directory, filename)
|
|
1034
|
+
self.download_file(
|
|
1035
|
+
"dependencies/{}/{}".format(package_name, platform_name),
|
|
1036
|
+
package_filepath,
|
|
1037
|
+
chunk_size=chunk_size,
|
|
1038
|
+
progress=progress
|
|
1039
|
+
)
|
|
1040
|
+
return package_filepath
|
|
1041
|
+
|
|
1042
|
+
def upload_dependency_package(
|
|
1043
|
+
self, filepath, package_name, platform_name=None, progress=None
|
|
1044
|
+
):
|
|
1045
|
+
if platform_name is None:
|
|
1046
|
+
platform_name = platform.system().lower()
|
|
1047
|
+
|
|
1048
|
+
self.upload_file(
|
|
1049
|
+
"dependencies/{}/{}".format(package_name, platform_name),
|
|
1050
|
+
filepath,
|
|
1051
|
+
progress=progress
|
|
1052
|
+
)
|
|
1053
|
+
|
|
1054
|
+
def delete_dependency_package(self, package_name, platform_name=None):
|
|
1055
|
+
if platform_name is None:
|
|
1056
|
+
platform_name = platform.system().lower()
|
|
1057
|
+
|
|
1058
|
+
response = self.delete(
|
|
1059
|
+
"dependencies/{}/{}".format(package_name, platform_name),
|
|
1060
|
+
)
|
|
1061
|
+
if response.status != 200:
|
|
1062
|
+
raise ServerError("Failed to delete dependency file")
|
|
1063
|
+
return response.data
|
|
1064
|
+
|
|
676
1065
|
# Anatomy presets
|
|
677
1066
|
def get_project_anatomy_presets(self, add_default=True):
|
|
678
1067
|
result = self.get("anatomy/presets")
|
|
@@ -713,13 +1102,32 @@ class ServerAPIBase(object):
|
|
|
713
1102
|
return full_settings
|
|
714
1103
|
return full_settings["settings"]
|
|
715
1104
|
|
|
716
|
-
def
|
|
1105
|
+
def get_addon_studio_settings(self, addon_name, addon_version):
|
|
1106
|
+
result = self.get(
|
|
1107
|
+
"addons/{}/{}/settings".format(addon_name, addon_version)
|
|
1108
|
+
)
|
|
1109
|
+
if result.status != 200:
|
|
1110
|
+
raise ServerError(result.text)
|
|
1111
|
+
return result.data
|
|
1112
|
+
|
|
1113
|
+
def get_addon_project_settings(
|
|
1114
|
+
self, addon_name, addon_version, project_name
|
|
1115
|
+
):
|
|
717
1116
|
result = self.get(
|
|
718
1117
|
"addons/{}/{}/settings/{}".format(
|
|
719
|
-
addon_name, addon_version, project_name
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
1118
|
+
addon_name, addon_version, project_name
|
|
1119
|
+
)
|
|
1120
|
+
)
|
|
1121
|
+
if result.status != 200:
|
|
1122
|
+
raise ServerError(result.text)
|
|
1123
|
+
return result.data
|
|
1124
|
+
|
|
1125
|
+
def get_addon_settings(self, addon_name, addon_version, project_name=None):
|
|
1126
|
+
if project_name is None:
|
|
1127
|
+
return self.get_addon_studio_settings(addon_name, addon_version)
|
|
1128
|
+
return self.get_addon_project_settings(
|
|
1129
|
+
addon_name, addon_version, project_name
|
|
1130
|
+
)
|
|
723
1131
|
|
|
724
1132
|
# Entity getters
|
|
725
1133
|
def get_rest_project(self, project_name):
|
|
@@ -1864,6 +2272,7 @@ class ServerAPIBase(object):
|
|
|
1864
2272
|
version_ids=[version_id],
|
|
1865
2273
|
active=None,
|
|
1866
2274
|
fields=fields,
|
|
2275
|
+
own_attributes=own_attributes
|
|
1867
2276
|
)
|
|
1868
2277
|
for representation in representations:
|
|
1869
2278
|
return representation
|
|
@@ -1919,7 +2328,7 @@ class ServerAPIBase(object):
|
|
|
1919
2328
|
fields=None,
|
|
1920
2329
|
own_attributes=False
|
|
1921
2330
|
):
|
|
1922
|
-
filters = {}
|
|
2331
|
+
filters = {"projectName": project_name}
|
|
1923
2332
|
if task_ids is not None:
|
|
1924
2333
|
task_ids = set(task_ids)
|
|
1925
2334
|
if not task_ids:
|
|
@@ -1944,7 +2353,7 @@ class ServerAPIBase(object):
|
|
|
1944
2353
|
if own_attributes:
|
|
1945
2354
|
fields.add("ownAttrib")
|
|
1946
2355
|
|
|
1947
|
-
query = workfiles_info_graphql_query()
|
|
2356
|
+
query = workfiles_info_graphql_query(fields)
|
|
1948
2357
|
|
|
1949
2358
|
for attr, filter_value in filters.items():
|
|
1950
2359
|
query.set_variable_value(attr, filter_value)
|
|
@@ -85,6 +85,41 @@ def get_server_api_connection():
|
|
|
85
85
|
return GlobalContext.get_server_api_connection()
|
|
86
86
|
|
|
87
87
|
|
|
88
|
+
def get_base_url():
|
|
89
|
+
con = get_server_api_connection()
|
|
90
|
+
return con.get_base_url()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_rest_url():
|
|
94
|
+
con = get_server_api_connection()
|
|
95
|
+
return con.get_rest_url()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def raw_get(*args, **kwargs):
|
|
99
|
+
con = get_server_api_connection()
|
|
100
|
+
return con.raw_get(*args, **kwargs)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def raw_post(*args, **kwargs):
|
|
104
|
+
con = get_server_api_connection()
|
|
105
|
+
return con.raw_post(*args, **kwargs)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def raw_put(*args, **kwargs):
|
|
109
|
+
con = get_server_api_connection()
|
|
110
|
+
return con.raw_put(*args, **kwargs)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def raw_patch(*args, **kwargs):
|
|
114
|
+
con = get_server_api_connection()
|
|
115
|
+
return con.raw_patch(*args, **kwargs)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def raw_delete(*args, **kwargs):
|
|
119
|
+
con = get_server_api_connection()
|
|
120
|
+
return con.raw_delete(*args, **kwargs)
|
|
121
|
+
|
|
122
|
+
|
|
88
123
|
def get(*args, **kwargs):
|
|
89
124
|
con = get_server_api_connection()
|
|
90
125
|
return con.get(*args, **kwargs)
|
|
@@ -110,6 +145,106 @@ def delete(*args, **kwargs):
|
|
|
110
145
|
return con.delete(*args, **kwargs)
|
|
111
146
|
|
|
112
147
|
|
|
148
|
+
def download_file(*args, **kwargs):
|
|
149
|
+
con = get_server_api_connection()
|
|
150
|
+
return con.download_file(*args, **kwargs)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def upload_file(*args, **kwargs):
|
|
154
|
+
con = get_server_api_connection()
|
|
155
|
+
return con.upload_file(*args, **kwargs)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def query_graphql(*args, **kwargs):
|
|
159
|
+
con = get_server_api_connection()
|
|
160
|
+
return con.query_graphql(*args, **kwargs)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def get_users(*args, **kwargs):
|
|
164
|
+
con = get_server_api_connection()
|
|
165
|
+
return con.get_users(*args, **kwargs)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_user(*args, **kwargs):
|
|
169
|
+
con = get_server_api_connection()
|
|
170
|
+
return con.get_user(*args, **kwargs)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def get_attributes_for_type(*args, **kwargs):
|
|
174
|
+
con = get_server_api_connection()
|
|
175
|
+
return con.get_attributes_for_type(*args, **kwargs)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def get_addons_info(*args, **kwargs):
|
|
179
|
+
con = get_server_api_connection()
|
|
180
|
+
return con.get_addons_info(*args, **kwargs)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def download_addon_private_file(*args, **kwargs):
|
|
184
|
+
con = get_server_api_connection()
|
|
185
|
+
return con.download_addon_private_file(*args, **kwargs)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def get_dependencies_info(*args, **kwargs):
|
|
189
|
+
con = get_server_api_connection()
|
|
190
|
+
return con.get_dependencies_info(*args, **kwargs)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def update_dependency_info(*args, **kwargs):
|
|
194
|
+
con = get_server_api_connection()
|
|
195
|
+
return con.update_dependency_info(*args, **kwargs)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def download_dependency_package(*args, **kwargs):
|
|
199
|
+
con = get_server_api_connection()
|
|
200
|
+
return con.download_dependency_package(*args, **kwargs)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def upload_dependency_package(*args, **kwargs):
|
|
204
|
+
con = get_server_api_connection()
|
|
205
|
+
return con.upload_dependency_package(*args, **kwargs)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def delete_dependency_package(*args, **kwargs):
|
|
209
|
+
con = get_server_api_connection()
|
|
210
|
+
return con.delete_dependency_package(*args, **kwargs)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def get_project_anatomy_presets(*args, **kwargs):
|
|
214
|
+
con = get_server_api_connection()
|
|
215
|
+
return con.get_project_anatomy_presets(*args, **kwargs)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def get_project_anatomy_preset(*args, **kwargs):
|
|
219
|
+
con = get_server_api_connection()
|
|
220
|
+
return con.get_project_anatomy_preset(*args, **kwargs)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def get_full_production_settings(*args, **kwargs):
|
|
224
|
+
con = get_server_api_connection()
|
|
225
|
+
return con.get_full_production_settings(*args, **kwargs)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def get_production_settings(*args, **kwargs):
|
|
229
|
+
con = get_server_api_connection()
|
|
230
|
+
return con.get_production_settings(*args, **kwargs)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def get_full_project_settings(*args, **kwargs):
|
|
234
|
+
con = get_server_api_connection()
|
|
235
|
+
return con.get_full_project_settings(*args, **kwargs)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def get_project_settings(*args, **kwargs):
|
|
239
|
+
con = get_server_api_connection()
|
|
240
|
+
return con.get_project_settings(*args, **kwargs)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def get_addon_settings(*args, **kwargs):
|
|
244
|
+
con = get_server_api_connection()
|
|
245
|
+
return con.get_addon_settings(*args, **kwargs)
|
|
246
|
+
|
|
247
|
+
|
|
113
248
|
def get_project(*args, **kwargs):
|
|
114
249
|
con = get_server_api_connection()
|
|
115
250
|
return con.get_project(*args, **kwargs)
|
|
@@ -245,16 +380,6 @@ def get_representations_parents(*args, **kwargs):
|
|
|
245
380
|
return con.get_representations_parents(*args, **kwargs)
|
|
246
381
|
|
|
247
382
|
|
|
248
|
-
def get_project_settings(*args, **kwargs):
|
|
249
|
-
con = get_server_api_connection()
|
|
250
|
-
return con.get_project_settings(*args, **kwargs)
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def get_addon_settings(*args, **kwargs):
|
|
254
|
-
con = get_server_api_connection()
|
|
255
|
-
return con.get_addon_settings(*args, **kwargs)
|
|
256
|
-
|
|
257
|
-
|
|
258
383
|
def create_project(
|
|
259
384
|
project_name,
|
|
260
385
|
project_code,
|
|
@@ -265,3 +265,102 @@ def validate_url(url):
|
|
|
265
265
|
title="Couldn't connect to server",
|
|
266
266
|
hints=hints + universal_hints
|
|
267
267
|
)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class TransferProgress:
|
|
271
|
+
"""Object to store progress of download/upload from/to server."""
|
|
272
|
+
|
|
273
|
+
def __init__(self):
|
|
274
|
+
self._started = False
|
|
275
|
+
self._done = False
|
|
276
|
+
self._downloaded = 0
|
|
277
|
+
self._content_size = None
|
|
278
|
+
|
|
279
|
+
self._failed = False
|
|
280
|
+
self._fail_reason = None
|
|
281
|
+
|
|
282
|
+
self._source_url = "N/A"
|
|
283
|
+
self._destination_url = "N/A"
|
|
284
|
+
|
|
285
|
+
def get_content_size(self):
|
|
286
|
+
return self._content_size
|
|
287
|
+
|
|
288
|
+
def set_content_size(self, content_size):
|
|
289
|
+
if self._content_size is not None:
|
|
290
|
+
raise ValueError("Content size was set more then once")
|
|
291
|
+
self._content_size = content_size
|
|
292
|
+
|
|
293
|
+
def get_started(self):
|
|
294
|
+
return self._started
|
|
295
|
+
|
|
296
|
+
def set_started(self):
|
|
297
|
+
if self._started:
|
|
298
|
+
raise ValueError("Progress already started")
|
|
299
|
+
self._started = True
|
|
300
|
+
|
|
301
|
+
def get_done(self):
|
|
302
|
+
return self._done
|
|
303
|
+
|
|
304
|
+
def set_done(self):
|
|
305
|
+
if self._done:
|
|
306
|
+
raise ValueError("Progress was already marked as done")
|
|
307
|
+
if not self._started:
|
|
308
|
+
raise ValueError("Progress didn't start yet")
|
|
309
|
+
self._done = True
|
|
310
|
+
|
|
311
|
+
def get_failed(self):
|
|
312
|
+
return self._failed
|
|
313
|
+
|
|
314
|
+
def get_fail_reason(self):
|
|
315
|
+
return self._fail_reason
|
|
316
|
+
|
|
317
|
+
def set_failed(self, reason):
|
|
318
|
+
self._fail_reason = reason
|
|
319
|
+
self._failed = True
|
|
320
|
+
|
|
321
|
+
def get_downloaded_size(self):
|
|
322
|
+
return self._downloaded
|
|
323
|
+
|
|
324
|
+
def set_downloaded_size(self, downloaded_size):
|
|
325
|
+
self._downloaded = downloaded_size
|
|
326
|
+
|
|
327
|
+
def add_downloaded_chunk(self, chunk_size):
|
|
328
|
+
self._downloaded += chunk_size
|
|
329
|
+
|
|
330
|
+
def get_source_url(self):
|
|
331
|
+
return self._source_url
|
|
332
|
+
|
|
333
|
+
def set_source_url(self, url):
|
|
334
|
+
self._source_url = url
|
|
335
|
+
|
|
336
|
+
def get_destination_url(self):
|
|
337
|
+
return self._destination_url
|
|
338
|
+
|
|
339
|
+
def set_destination_url(self, url):
|
|
340
|
+
self._destination_url = url
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
def is_running(self):
|
|
344
|
+
if (
|
|
345
|
+
not self.started
|
|
346
|
+
or self.done
|
|
347
|
+
or self.failed
|
|
348
|
+
):
|
|
349
|
+
return False
|
|
350
|
+
return True
|
|
351
|
+
|
|
352
|
+
@property
|
|
353
|
+
def progress(self):
|
|
354
|
+
if self._content_size is None:
|
|
355
|
+
return None
|
|
356
|
+
return (self._downloaded * 100.0) / float(self._content_size)
|
|
357
|
+
|
|
358
|
+
content_size = property(get_content_size, set_content_size)
|
|
359
|
+
started = property(get_started)
|
|
360
|
+
done = property(get_done)
|
|
361
|
+
failed = property(get_failed)
|
|
362
|
+
fail_reason = property(get_fail_reason)
|
|
363
|
+
source_url = property(get_source_url, set_source_url)
|
|
364
|
+
destination_url = property(get_destination_url, set_destination_url)
|
|
365
|
+
content_size = property(get_content_size, set_content_size)
|
|
366
|
+
downloaded_size = property(get_downloaded_size, set_downloaded_size)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Package declaring Python API for Ayon server."""
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.7"
|
|
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
|
|
File without changes
|
|
File without changes
|
{ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|