Ayon-Python-Api 0.4.2__tar.gz → 0.5.0__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 (23) hide show
  1. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/PKG-INFO +1 -1
  2. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/_api.py +6 -4
  3. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/graphql_queries.py +1 -0
  4. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/server_api.py +77 -35
  5. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/utils.py +37 -12
  6. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/version.py +1 -1
  7. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_python_api.egg-info/PKG-INFO +1 -1
  8. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/pyproject.toml +1 -1
  9. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/LICENSE +0 -0
  10. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/README.md +0 -0
  11. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/__init__.py +0 -0
  12. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/constants.py +0 -0
  13. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/entity_hub.py +0 -0
  14. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/events.py +0 -0
  15. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/exceptions.py +0 -0
  16. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/graphql.py +0 -0
  17. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_api/operations.py +0 -0
  18. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_python_api.egg-info/SOURCES.txt +0 -0
  19. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_python_api.egg-info/dependency_links.txt +0 -0
  20. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_python_api.egg-info/requires.txt +0 -0
  21. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/ayon_python_api.egg-info/top_level.txt +0 -0
  22. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/setup.cfg +0 -0
  23. {ayon-python-api-0.4.2 → ayon-python-api-0.5.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ayon-python-api
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: AYON Python API
5
5
  Home-page: https://github.com/ynput/ayon-python-api
6
6
  Author: ynput.io
@@ -602,12 +602,12 @@ def delete_installer(*args, **kwargs):
602
602
 
603
603
  def download_installer(*args, **kwargs):
604
604
  con = get_server_api_connection()
605
- con.download_installer(*args, **kwargs)
605
+ return con.download_installer(*args, **kwargs)
606
606
 
607
607
 
608
608
  def upload_installer(*args, **kwargs):
609
609
  con = get_server_api_connection()
610
- con.upload_installer(*args, **kwargs)
610
+ return con.upload_installer(*args, **kwargs)
611
611
 
612
612
 
613
613
  # Dependency packages
@@ -978,12 +978,14 @@ def delete_project(project_name):
978
978
 
979
979
  def get_thumbnail_by_id(project_name, thumbnail_id):
980
980
  con = get_server_api_connection()
981
- con.get_thumbnail_by_id(project_name, thumbnail_id)
981
+ return con.get_thumbnail_by_id(project_name, thumbnail_id)
982
982
 
983
983
 
984
984
  def get_thumbnail(project_name, entity_type, entity_id, thumbnail_id=None):
985
985
  con = get_server_api_connection()
986
- con.get_thumbnail(project_name, entity_type, entity_id, thumbnail_id)
986
+ return con.get_thumbnail(
987
+ project_name, entity_type, entity_id, thumbnail_id
988
+ )
987
989
 
988
990
 
989
991
  def get_folder_thumbnail(project_name, folder_id, thumbnail_id=None):
@@ -144,6 +144,7 @@ def product_types_query(fields):
144
144
  query_queue.append((k, v, field))
145
145
  return query
146
146
 
147
+
147
148
  def project_product_types_query(fields):
148
149
  query = GraphQlQuery("ProjectProductTypes")
149
150
  project_query = query.add_field("project")
@@ -931,8 +931,8 @@ class ServerAPI(object):
931
931
  int(re_match.group("major")),
932
932
  int(re_match.group("minor")),
933
933
  int(re_match.group("patch")),
934
- re_match.group("prerelease"),
935
- re_match.group("buildmetadata")
934
+ re_match.group("prerelease") or "",
935
+ re_match.group("buildmetadata") or "",
936
936
  )
937
937
  return self._server_version_tuple
938
938
 
@@ -1133,31 +1133,41 @@ class ServerAPI(object):
1133
1133
 
1134
1134
  response = None
1135
1135
  new_response = None
1136
- for _ in range(max_retries):
1136
+ for retry_idx in reversed(range(max_retries)):
1137
1137
  try:
1138
1138
  response = function(url, **kwargs)
1139
1139
  break
1140
1140
 
1141
1141
  except ConnectionRefusedError:
1142
+ if retry_idx == 0:
1143
+ self.log.warning(
1144
+ "Connection error happened.", exc_info=True
1145
+ )
1146
+
1142
1147
  # Server may be restarting
1143
1148
  new_response = RestApiResponse(
1144
1149
  None,
1145
1150
  {"detail": "Unable to connect the server. Connection refused"}
1146
1151
  )
1152
+
1147
1153
  except requests.exceptions.Timeout:
1148
1154
  # Connection timed out
1149
1155
  new_response = RestApiResponse(
1150
1156
  None,
1151
1157
  {"detail": "Connection timed out."}
1152
1158
  )
1159
+
1153
1160
  except requests.exceptions.ConnectionError:
1154
- # Other connection error (ssl, etc) - does not make sense to
1155
- # try call server again
1161
+ # Log warning only on last attempt
1162
+ if retry_idx == 0:
1163
+ self.log.warning(
1164
+ "Connection error happened.", exc_info=True
1165
+ )
1166
+
1156
1167
  new_response = RestApiResponse(
1157
1168
  None,
1158
1169
  {"detail": "Unable to connect the server. Connection error"}
1159
1170
  )
1160
- break
1161
1171
 
1162
1172
  time.sleep(0.1)
1163
1173
 
@@ -1342,7 +1352,9 @@ class ServerAPI(object):
1342
1352
  status=None,
1343
1353
  description=None,
1344
1354
  summary=None,
1345
- payload=None
1355
+ payload=None,
1356
+ progress=None,
1357
+ retries=None
1346
1358
  ):
1347
1359
  kwargs = {
1348
1360
  key: value
@@ -1353,9 +1365,27 @@ class ServerAPI(object):
1353
1365
  ("description", description),
1354
1366
  ("summary", summary),
1355
1367
  ("payload", payload),
1368
+ ("progress", progress),
1369
+ ("retries", retries),
1356
1370
  )
1357
1371
  if value is not None
1358
1372
  }
1373
+ # 'progress' and 'retries' are available since 0.5.x server version
1374
+ major, minor, _, _, _ = self.server_version_tuple
1375
+ if (major, minor) < (0, 5):
1376
+ args = []
1377
+ if progress is not None:
1378
+ args.append("progress")
1379
+ if retries is not None:
1380
+ args.append("retries")
1381
+ fields = ", ".join("'{}'".format(f) for f in args)
1382
+ ending = "s" if len(args) > 1 else ""
1383
+ raise ValueError((
1384
+ "Your server version '{}' does not support update"
1385
+ " of {} field{} on event. The fields are supported since"
1386
+ " server version '0.5'."
1387
+ ).format(self.get_server_version(), fields, ending))
1388
+
1359
1389
  response = self.patch(
1360
1390
  "events/{}".format(event_id),
1361
1391
  **kwargs
@@ -1427,6 +1457,7 @@ class ServerAPI(object):
1427
1457
  description=None,
1428
1458
  sequential=None,
1429
1459
  events_filter=None,
1460
+ max_retries=None,
1430
1461
  ):
1431
1462
  """Enroll job based on events.
1432
1463
 
@@ -1468,8 +1499,12 @@ class ServerAPI(object):
1468
1499
  in target event.
1469
1500
  sequential (Optional[bool]): The source topic must be processed
1470
1501
  in sequence.
1471
- events_filter (Optional[ayon_server.sqlfilter.Filter]): A dict-like
1472
- with conditions to filter the source event.
1502
+ events_filter (Optional[dict[str, Any]]): Filtering conditions
1503
+ to filter the source event. For more technical specifications
1504
+ look to server backed 'ayon_server.sqlfilter.Filter'.
1505
+ TODO: Add example of filters.
1506
+ max_retries (Optional[int]): How many times can be event retried.
1507
+ Default value is based on server (3 at the time of this PR).
1473
1508
 
1474
1509
  Returns:
1475
1510
  Union[None, dict[str, Any]]: None if there is no event matching
@@ -1480,6 +1515,7 @@ class ServerAPI(object):
1480
1515
  "sourceTopic": source_topic,
1481
1516
  "targetTopic": target_topic,
1482
1517
  "sender": sender,
1518
+ "maxRetries": max_retries,
1483
1519
  }
1484
1520
  if sequential is not None:
1485
1521
  kwargs["sequential"] = sequential
@@ -2229,6 +2265,34 @@ class ServerAPI(object):
2229
2265
  response.raise_for_status("Failed to create/update dependency")
2230
2266
  return response.data
2231
2267
 
2268
+ def _get_dependency_package_route(
2269
+ self, filename=None, platform_name=None
2270
+ ):
2271
+ major, minor, patch, _, _ = self.server_version_tuple
2272
+ if (major, minor, patch) <= (0, 2, 0):
2273
+ # Backwards compatibility for AYON server 0.2.0 and lower
2274
+ self.log.warning((
2275
+ "Using deprecated dependency package route."
2276
+ " Please update your AYON server to version 0.2.1 or higher."
2277
+ " Backwards compatibility for this route will be removed"
2278
+ " in future releases of ayon-python-api."
2279
+ ))
2280
+ if platform_name is None:
2281
+ platform_name = platform.system().lower()
2282
+ base = "dependencies"
2283
+ if not filename:
2284
+ return base
2285
+ return "{}/{}/{}".format(base, filename, platform_name)
2286
+
2287
+ if (major, minor) <= (0, 3):
2288
+ endpoint = "desktop/dependency_packages"
2289
+ else:
2290
+ endpoint = "desktop/dependencyPackages"
2291
+
2292
+ if filename:
2293
+ return "{}/{}".format(endpoint, filename)
2294
+ return endpoint
2295
+
2232
2296
  def get_dependency_packages(self):
2233
2297
  """Information about dependency packages on server.
2234
2298
 
@@ -2256,33 +2320,11 @@ class ServerAPI(object):
2256
2320
  server.
2257
2321
  """
2258
2322
 
2259
- endpoint = "desktop/dependencyPackages"
2260
- major, minor, _, _, _ = self.server_version_tuple
2261
- if major == 0 and minor <= 3:
2262
- endpoint = "desktop/dependency_packages"
2263
-
2323
+ endpoint = self._get_dependency_package_route()
2264
2324
  result = self.get(endpoint)
2265
2325
  result.raise_for_status()
2266
2326
  return result.data
2267
2327
 
2268
- def _get_dependency_package_route(
2269
- self, filename=None, platform_name=None
2270
- ):
2271
- major, minor, patch, _, _ = self.server_version_tuple
2272
- if major == 0 and (minor > 2 or (minor == 2 and patch >= 1)):
2273
- base = "desktop/dependency_packages"
2274
- if not filename:
2275
- return base
2276
- return "{}/{}".format(base, filename)
2277
-
2278
- # Backwards compatibility for AYON server 0.2.0 and lower
2279
- if platform_name is None:
2280
- platform_name = platform.system().lower()
2281
- base = "dependencies"
2282
- if not filename:
2283
- return base
2284
- return "{}/{}/{}".format(base, filename, platform_name)
2285
-
2286
2328
  def create_dependency_package(
2287
2329
  self,
2288
2330
  filename,
@@ -4323,9 +4365,6 @@ class ServerAPI(object):
4323
4365
  fields.remove("attrib")
4324
4366
  fields |= self.get_attributes_fields_for_type("version")
4325
4367
 
4326
- if active is not None:
4327
- fields.add("active")
4328
-
4329
4368
  # Make sure fields have minimum required fields
4330
4369
  fields |= {"id", "version"}
4331
4370
 
@@ -4334,6 +4373,9 @@ class ServerAPI(object):
4334
4373
  use_rest = True
4335
4374
  fields = {"id"}
4336
4375
 
4376
+ if active is not None:
4377
+ fields.add("active")
4378
+
4337
4379
  if own_attributes:
4338
4380
  fields.add("ownAttrib")
4339
4381
 
@@ -263,19 +263,23 @@ def _try_connect_to_server(url, timeout=None):
263
263
  return True
264
264
 
265
265
 
266
- def login_to_server(url, username, password):
266
+ def login_to_server(url, username, password, timeout=None):
267
267
  """Use login to the server to receive token.
268
268
 
269
269
  Args:
270
270
  url (str): Server url.
271
271
  username (str): User's username.
272
272
  password (str): User's password.
273
+ timeout (Optional[float]): Timeout for request. Value from
274
+ 'get_default_timeout' is used if not specified.
273
275
 
274
276
  Returns:
275
277
  Union[str, None]: User's token if login was successfull.
276
278
  Otherwise 'None'.
277
279
  """
278
280
 
281
+ if timeout is None:
282
+ timeout = get_default_timeout()
279
283
  headers = {"Content-Type": "application/json"}
280
284
  response = requests.post(
281
285
  "{}/api/auth/login".format(url),
@@ -283,7 +287,8 @@ def login_to_server(url, username, password):
283
287
  json={
284
288
  "name": username,
285
289
  "password": password
286
- }
290
+ },
291
+ timeout=timeout,
287
292
  )
288
293
  token = None
289
294
  # 200 - success
@@ -294,44 +299,64 @@ def login_to_server(url, username, password):
294
299
  return token
295
300
 
296
301
 
297
- def logout_from_server(url, token):
302
+ def logout_from_server(url, token, timeout=None):
298
303
  """Logout from server and throw token away.
299
304
 
300
305
  Args:
301
306
  url (str): Url from which should be logged out.
302
307
  token (str): Token which should be used to log out.
308
+ timeout (Optional[float]): Timeout for request. Value from
309
+ 'get_default_timeout' is used if not specified.
303
310
  """
304
311
 
312
+ if timeout is None:
313
+ timeout = get_default_timeout()
305
314
  headers = {
306
315
  "Content-Type": "application/json",
307
316
  "Authorization": "Bearer {}".format(token)
308
317
  }
309
318
  requests.post(
310
319
  url + "/api/auth/logout",
311
- headers=headers
320
+ headers=headers,
321
+ timeout=timeout,
312
322
  )
313
323
 
314
324
 
315
- def is_token_valid(url, token):
325
+ def is_token_valid(url, token, timeout=None):
316
326
  """Check if token is valid.
317
327
 
328
+ Token can be a user token or service api key.
329
+
318
330
  Args:
319
331
  url (str): Server url.
320
332
  token (str): User's token.
333
+ timeout (Optional[float]): Timeout for request. Value from
334
+ 'get_default_timeout' is used if not specified.
321
335
 
322
336
  Returns:
323
337
  bool: True if token is valid.
324
338
  """
325
339
 
326
- headers = {
340
+ if timeout is None:
341
+ timeout = get_default_timeout()
342
+
343
+ base_headers = {
327
344
  "Content-Type": "application/json",
328
- "Authorization": "Bearer {}".format(token)
329
345
  }
330
- response = requests.get(
331
- "{}/api/users/me".format(url),
332
- headers=headers
333
- )
334
- return response.status_code == 200
346
+ for header_value in (
347
+ {"Authorization": "Bearer {}".format(token)},
348
+ {"X-Api-Key": token},
349
+ ):
350
+ headers = base_headers.copy()
351
+ headers.update(header_value)
352
+ response = requests.get(
353
+ "{}/api/users/me".format(url),
354
+ headers=headers,
355
+ timeout=timeout,
356
+ )
357
+ if response.status_code == 200:
358
+ return True
359
+ return False
335
360
 
336
361
 
337
362
  def validate_url(url, timeout=None):
@@ -1,2 +1,2 @@
1
1
  """Package declaring Python API for Ayon server."""
2
- __version__ = "0.4.2"
2
+ __version__ = "0.5.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ayon-python-api
3
- Version: 0.4.2
3
+ Version: 0.5.0
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
  [project]
2
2
  name = "ayon-python-api"
3
- version = "0.4.2"
3
+ version = "0.5.0"
4
4
  description = "AYON Python API"
5
5
  license = {file = "LICENSE"}
6
6
  readme = {file = "README.md", content-type = "text/markdown"}
File without changes