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.
Files changed (24) hide show
  1. {ayon-python-api-0.1.4/ayon_python_api.egg-info → ayon-python-api-0.1.7}/PKG-INFO +1 -1
  2. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/__init__.py +83 -3
  3. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/server.py +427 -18
  4. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/server_api.py +135 -10
  5. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/utils.py +99 -0
  6. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/version.py +1 -1
  7. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7/ayon_python_api.egg-info}/PKG-INFO +1 -1
  8. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/pyproject.toml +1 -1
  9. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/setup.py +1 -1
  10. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/LICENSE +0 -0
  11. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/README.md +0 -0
  12. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/constants.py +0 -0
  13. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/entity_hub.py +0 -0
  14. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/events.py +0 -0
  15. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/exceptions.py +0 -0
  16. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/graphql.py +0 -0
  17. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/graphql_queries.py +0 -0
  18. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/operations.py +0 -0
  19. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_api/thumbnails.py +0 -0
  20. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/SOURCES.txt +0 -0
  21. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/dependency_links.txt +0 -0
  22. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/requires.txt +0 -0
  23. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/ayon_python_api.egg-info/top_level.txt +0 -0
  24. {ayon-python-api-0.1.4 → ayon-python-api-0.1.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ayon-python-api
3
- Version: 0.1.4
3
+ Version: 0.1.7
4
4
  Summary: AYON Python API
5
5
  Home-page: https://github.com/ynput/ayon-python-api
6
6
  Author: ynput.io
@@ -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__(self, base_url, token=None):
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
- self.get_user_info()
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.get_user_info()
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 get_user_info(self):
283
- user_info = self._get_user_info()
284
- if user_info is None:
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 user_info
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
- headers = {"Content-Type": content_type}
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.get_user_info()
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 get_addon_settings(self, addon_name, addon_version, project_name):
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
- if result.status == 200:
721
- return result.data
722
- return None
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.4"
2
+ __version__ = "0.1.7"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ayon-python-api
3
- Version: 0.1.4
3
+ Version: 0.1.7
4
4
  Summary: AYON Python API
5
5
  Home-page: https://github.com/ynput/ayon-python-api
6
6
  Author: ynput.io
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ayon_api"
3
- version = "0.1.4"
3
+ version = "0.1.7"
4
4
  description = "Python api for AYON server"
5
5
  authors = ["ynput.io <info@ynput.io>"]
6
6
 
@@ -34,5 +34,5 @@ setup(
34
34
  dependency_links=[
35
35
  "appdirs @ git+https://github.com/ActiveState/appdirs.git@master"
36
36
  ],
37
- keywords=["AYON", "ynput", "OpenPype", "vfx"]
37
+ keywords=["AYON", "ynput", "OpenPype", "vfx"],
38
38
  )
File without changes