ayon-python-api 1.2.16.dev0__py3-none-any.whl → 1.2.17__py3-none-any.whl

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_api/utils.py CHANGED
@@ -12,9 +12,9 @@ import platform
12
12
  import traceback
13
13
  import collections
14
14
  import itertools
15
- from urllib.parse import urlparse, urlencode
15
+ from urllib.parse import urlparse, urlencode, ParseResult
16
16
  import typing
17
- from typing import Optional, Any, Iterable, Union
17
+ from typing import Any, Iterable
18
18
  from enum import IntEnum
19
19
 
20
20
  import requests
@@ -27,6 +27,7 @@ from .constants import (
27
27
  )
28
28
  from .exceptions import (
29
29
  UrlError,
30
+ UrlNotReached,
30
31
  ServerError,
31
32
  UnauthorizedError,
32
33
  HTTPRequestError,
@@ -148,7 +149,7 @@ class RestApiResponse:
148
149
  return self._response.content
149
150
 
150
151
  @property
151
- def content_type(self) -> Optional[str]:
152
+ def content_type(self) -> str | None:
152
153
  return self.headers.get("Content-Type")
153
154
 
154
155
  @property
@@ -256,7 +257,7 @@ def fill_own_attribs(entity: AnyEntityDict) -> None:
256
257
  own_attrib[key] = copy.deepcopy(value)
257
258
 
258
259
 
259
- def _convert_list_filter_value(value: Any) -> Optional[list[Any]]:
260
+ def _convert_filter_value(value: Any) -> list[Any] | None:
260
261
  if value is None:
261
262
  return None
262
263
 
@@ -272,7 +273,7 @@ def prepare_list_filters(
272
273
  output: dict[str, Any], *args: tuple[str, Any], **kwargs: Any
273
274
  ) -> bool:
274
275
  for key, value in itertools.chain(args, kwargs.items()):
275
- value = _convert_list_filter_value(value)
276
+ value = _convert_filter_value(value)
276
277
  if value is None:
277
278
  continue
278
279
  if not value:
@@ -318,11 +319,11 @@ def get_machine_name() -> str:
318
319
  return unidecode.unidecode(platform.node())
319
320
 
320
321
 
321
- def get_default_site_id() -> Optional[str]:
322
+ def get_default_site_id() -> str | None:
322
323
  """Site id used for server connection.
323
324
 
324
325
  Returns:
325
- Optional[str]: Site id from environment variable or None.
326
+ str | None: Site id from environment variable or None.
326
327
 
327
328
  """
328
329
  return os.environ.get(SITE_ID_ENV_KEY)
@@ -333,25 +334,25 @@ class ThumbnailContent:
333
334
 
334
335
  Args:
335
336
  project_name (str): Project name.
336
- thumbnail_id (Optional[str]): Thumbnail id.
337
- content (Optional[bytes]): Thumbnail content.
338
- content_type (Optional[str]): Content type e.g. 'image/png'.
337
+ thumbnail_id (str | None): Thumbnail id.
338
+ content (bytes | None): Thumbnail content.
339
+ content_type (str | None): Content type e.g. 'image/png'.
339
340
 
340
341
  """
341
342
  def __init__(
342
343
  self,
343
344
  project_name: str,
344
- thumbnail_id: Optional[str],
345
- content: Optional[bytes],
346
- content_type: Optional[str],
345
+ thumbnail_id: str | None,
346
+ content: bytes | None,
347
+ content_type: str | None,
347
348
  ):
348
349
  self.project_name: str = project_name
349
- self.thumbnail_id: Optional[str] = thumbnail_id
350
- self.content_type: Optional[str] = content_type
350
+ self.thumbnail_id: str | None = thumbnail_id
351
+ self.content_type: str | None = content_type
351
352
  self.content: bytes = content or b""
352
353
 
353
354
  @property
354
- def id(self) -> str:
355
+ def id(self) -> str | None:
355
356
  """Wrapper for thumbnail id."""
356
357
  return self.thumbnail_id
357
358
 
@@ -394,14 +395,14 @@ def prepare_query_string(
394
395
 
395
396
  if not key_values:
396
397
  return ""
397
- return "?{}".format(urlencode(key_values))
398
+ return f"?{urlencode(key_values)}"
398
399
 
399
400
 
400
401
  def create_entity_id() -> str:
401
402
  return uuid.uuid1().hex
402
403
 
403
404
 
404
- def convert_entity_id(entity_id) -> Optional[str]:
405
+ def convert_entity_id(entity_id) -> str | None:
405
406
  if not entity_id:
406
407
  return None
407
408
 
@@ -416,7 +417,7 @@ def convert_entity_id(entity_id) -> Optional[str]:
416
417
  return None
417
418
 
418
419
 
419
- def convert_or_create_entity_id(entity_id: Optional[str] = None) -> str:
420
+ def convert_or_create_entity_id(entity_id: str | None = None) -> str:
420
421
  output = convert_entity_id(entity_id)
421
422
  if output is None:
422
423
  output = create_entity_id()
@@ -428,7 +429,7 @@ def entity_data_json_default(value: Any) -> Any:
428
429
  return int(value.timestamp())
429
430
 
430
431
  raise TypeError(
431
- "Object of type {} is not JSON serializable".format(str(type(value)))
432
+ f"Object of type {type(value)} is not JSON serializable"
432
433
  )
433
434
 
434
435
 
@@ -440,7 +441,7 @@ def slugify_string(
440
441
  min_length: int = 1,
441
442
  lower: bool = False,
442
443
  make_set: bool = False,
443
- ) -> Union[str, set[str]]:
444
+ ) -> str | set[str]:
444
445
  """Slugify a text string.
445
446
 
446
447
  This function removes transliterates input string to ASCII, removes
@@ -460,8 +461,7 @@ def slugify_string(
460
461
  min_length (int): Minimal length of an element (word).
461
462
 
462
463
  Returns:
463
- Union[str, set[str]]: Based on 'make_set' value returns slugified
464
- string.
464
+ str | set[str]: Based on 'make_set' value returns slugified string.
465
465
 
466
466
  """
467
467
  tmp_string = unidecode.unidecode(input_string)
@@ -486,14 +486,14 @@ def slugify_string(
486
486
 
487
487
 
488
488
  def failed_json_default(value: Any) -> str:
489
- return "< Failed value {} > {}".format(type(value), str(value))
489
+ return f"< Failed value {type(value)} > {value}"
490
490
 
491
491
 
492
492
  def prepare_attribute_changes(
493
493
  old_entity: AnyEntityDict,
494
494
  new_entity: AnyEntityDict,
495
495
  replace: int = False,
496
- ):
496
+ ) -> dict[str, Any]:
497
497
  attrib_changes = {}
498
498
  new_attrib = new_entity.get("attrib")
499
499
  old_attrib = old_entity.get("attrib")
@@ -544,7 +544,7 @@ def prepare_entity_changes(
544
544
  return changes
545
545
 
546
546
 
547
- def _try_parse_url(url: str) -> Optional[str]:
547
+ def _try_parse_url(url: str) -> ParseResult | None:
548
548
  try:
549
549
  return urlparse(url)
550
550
  except BaseException:
@@ -553,10 +553,10 @@ def _try_parse_url(url: str) -> Optional[str]:
553
553
 
554
554
  def _try_connect_to_server(
555
555
  url: str,
556
- timeout: Optional[float],
557
- verify: Optional[Union[str, bool]],
558
- cert: Optional[str],
559
- ) -> Optional[str]:
556
+ timeout: float | None,
557
+ verify: str | bool | None,
558
+ cert: str | None,
559
+ ) -> str | None:
560
560
  if timeout is None:
561
561
  timeout = get_default_timeout()
562
562
 
@@ -570,11 +570,12 @@ def _try_connect_to_server(
570
570
  # TODO add validation if the url lead to AYON server
571
571
  # - this won't validate if the url lead to 'google.com'
572
572
  response = requests.get(
573
- url,
573
+ f"{url}/api/info",
574
574
  timeout=timeout,
575
575
  verify=verify,
576
576
  cert=cert,
577
577
  )
578
+ _ = response.json()
578
579
  if response.history:
579
580
  return response.history[-1].headers["location"].rstrip("/")
580
581
  return url
@@ -590,19 +591,19 @@ def login_to_server(
590
591
  url: str,
591
592
  username: str,
592
593
  password: str,
593
- timeout: Optional[float] = None,
594
- ) -> Optional[str]:
594
+ timeout: float | None = None,
595
+ ) -> str | None:
595
596
  """Use login to the server to receive token.
596
597
 
597
598
  Args:
598
599
  url (str): Server url.
599
600
  username (str): User's username.
600
601
  password (str): User's password.
601
- timeout (Optional[float]): Timeout for request. Value from
602
+ timeout (float | None): Timeout for request. Value from
602
603
  'get_default_timeout' is used if not specified.
603
604
 
604
605
  Returns:
605
- Optional[str]: User's token if login was successfull.
606
+ str | None: User's token if login was successfull.
606
607
  Otherwise 'None'.
607
608
 
608
609
  """
@@ -610,7 +611,7 @@ def login_to_server(
610
611
  timeout = get_default_timeout()
611
612
  headers = {"Content-Type": "application/json"}
612
613
  response = requests.post(
613
- "{}/api/auth/login".format(url),
614
+ f"{url}/api/auth/login",
614
615
  headers=headers,
615
616
  json={
616
617
  "name": username,
@@ -627,13 +628,17 @@ def login_to_server(
627
628
  return token
628
629
 
629
630
 
630
- def logout_from_server(url: str, token: str, timeout: Optional[float] = None):
631
+ def logout_from_server(
632
+ url: str,
633
+ token: str,
634
+ timeout: float | None = None,
635
+ ) -> None:
631
636
  """Logout from server and throw token away.
632
637
 
633
638
  Args:
634
639
  url (str): Url from which should be logged out.
635
640
  token (str): Token which should be used to log out.
636
- timeout (Optional[float]): Timeout for request. Value from
641
+ timeout (float | None): Timeout for request. Value from
637
642
  'get_default_timeout' is used if not specified.
638
643
 
639
644
  """
@@ -641,10 +646,10 @@ def logout_from_server(url: str, token: str, timeout: Optional[float] = None):
641
646
  timeout = get_default_timeout()
642
647
  headers = {
643
648
  "Content-Type": "application/json",
644
- "Authorization": "Bearer {}".format(token)
649
+ "Authorization": f"Bearer {token}",
645
650
  }
646
651
  requests.post(
647
- url + "/api/auth/logout",
652
+ f"{url}/api/auth/logout",
648
653
  headers=headers,
649
654
  timeout=timeout,
650
655
  )
@@ -653,18 +658,18 @@ def logout_from_server(url: str, token: str, timeout: Optional[float] = None):
653
658
  def get_user_by_token(
654
659
  url: str,
655
660
  token: str,
656
- timeout: Optional[float] = None,
657
- ) -> Optional[dict[str, Any]]:
661
+ timeout: float | None = None,
662
+ ) -> dict[str, Any] | None:
658
663
  """Get user information by url and token.
659
664
 
660
665
  Args:
661
666
  url (str): Server url.
662
667
  token (str): User's token.
663
- timeout (Optional[float]): Timeout for request. Value from
668
+ timeout (float | None): Timeout for request. Value from
664
669
  'get_default_timeout' is used if not specified.
665
670
 
666
671
  Returns:
667
- Optional[dict[str, Any]]: User information if url and token are valid.
672
+ dict[str, Any] | None: User information if url and token are valid.
668
673
 
669
674
  """
670
675
  if timeout is None:
@@ -674,13 +679,13 @@ def get_user_by_token(
674
679
  "Content-Type": "application/json",
675
680
  }
676
681
  for header_value in (
677
- {"Authorization": "Bearer {}".format(token)},
682
+ {"Authorization": f"Bearer {token}"},
678
683
  {"X-Api-Key": token},
679
684
  ):
680
685
  headers = base_headers.copy()
681
686
  headers.update(header_value)
682
687
  response = requests.get(
683
- "{}/api/users/me".format(url),
688
+ f"{url}/api/users/me",
684
689
  headers=headers,
685
690
  timeout=timeout,
686
691
  )
@@ -692,7 +697,7 @@ def get_user_by_token(
692
697
  def is_token_valid(
693
698
  url: str,
694
699
  token: str,
695
- timeout: Optional[float] = None,
700
+ timeout: float | None = None,
696
701
  ) -> bool:
697
702
  """Check if token is valid.
698
703
 
@@ -701,7 +706,7 @@ def is_token_valid(
701
706
  Args:
702
707
  url (str): Server url.
703
708
  token (str): User's token.
704
- timeout (Optional[float]): Timeout for request. Value from
709
+ timeout (float | None): Timeout for request. Value from
705
710
  'get_default_timeout' is used if not specified.
706
711
 
707
712
  Returns:
@@ -715,9 +720,9 @@ def is_token_valid(
715
720
 
716
721
  def validate_url(
717
722
  url: str,
718
- timeout: Optional[int] = None,
719
- verify: Optional[Union[str, bool]] = None,
720
- cert: Optional[str] = None,
723
+ timeout: int | None = None,
724
+ verify: str | bool | None = None,
725
+ cert: str | None = None,
721
726
  ) -> str:
722
727
  """Validate url if is valid and server is available.
723
728
 
@@ -740,7 +745,7 @@ def validate_url(
740
745
 
741
746
  Args:
742
747
  url (str): Server url.
743
- timeout (Optional[int]): Timeout in seconds for connection to server.
748
+ timeout (int | None): Timeout in seconds for connection to server.
744
749
 
745
750
  Returns:
746
751
  Url which was used to connect to server.
@@ -749,8 +754,8 @@ def validate_url(
749
754
  UrlError: Error with short description and hints for user.
750
755
 
751
756
  """
752
- stripperd_url = url.strip()
753
- if not stripperd_url:
757
+ stripped_url = url.strip()
758
+ if not stripped_url:
754
759
  raise UrlError(
755
760
  "Invalid url format. Url is empty.",
756
761
  title="Invalid url format",
@@ -758,25 +763,30 @@ def validate_url(
758
763
  )
759
764
 
760
765
  # Not sure if this is good idea?
761
- modified_url = stripperd_url.rstrip("/")
766
+ modified_url = stripped_url.rstrip("/")
767
+
768
+ # Make sure url has http scheme
769
+ if not modified_url.lower().startswith("http"):
770
+ modified_url = f"http://{modified_url}"
771
+
762
772
  parsed_url = _try_parse_url(modified_url)
763
773
  universal_hints = [
764
774
  "does the url work in browser?"
765
775
  ]
766
776
  if parsed_url is None:
767
777
  raise UrlError(
768
- "Invalid url format. Url cannot be parsed as url \"{}\".".format(
769
- modified_url
778
+ (
779
+ "Invalid url format. Url cannot be parsed"
780
+ f" as url \"{modified_url}\"."
770
781
  ),
771
782
  title="Invalid url format",
772
783
  hints=universal_hints
773
784
  )
774
785
 
775
- # Try add 'https://' scheme if is missing
776
- # - this will trigger UrlError if both will crash
777
- if not parsed_url.scheme:
786
+ pathless_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
787
+ if parsed_url.path:
778
788
  new_url = _try_connect_to_server(
779
- "http://" + modified_url,
789
+ pathless_url,
780
790
  timeout=timeout,
781
791
  verify=verify,
782
792
  cert=cert,
@@ -794,17 +804,11 @@ def validate_url(
794
804
  return new_url
795
805
 
796
806
  hints = []
797
- if "/" in parsed_url.path or not parsed_url.scheme:
798
- new_path = parsed_url.path.split("/")[0]
799
- if not parsed_url.scheme:
800
- new_path = "https://" + new_path
801
-
802
- hints.append(
803
- "did you mean \"{}\"?".format(parsed_url.scheme + new_path)
804
- )
807
+ if parsed_url.path:
808
+ hints.append(f"did you mean \"{pathless_url}\"?")
805
809
 
806
- raise UrlError(
807
- "Couldn't connect to server on \"{}\"".format(url),
810
+ raise UrlNotReached(
811
+ f"Couldn't connect to server on \"{url}\"",
808
812
  title="Couldn't connect to server",
809
813
  hints=hints + universal_hints
810
814
  )
@@ -818,25 +822,25 @@ class TransferProgress:
818
822
  self._started: bool = False
819
823
  self._transfer_done: bool = False
820
824
  self._transferred: int = 0
821
- self._content_size: Optional[int] = None
825
+ self._content_size: int | None = None
822
826
 
823
827
  self._failed: bool = False
824
- self._fail_reason: Optional[str] = None
828
+ self._fail_reason: str | None = None
825
829
 
826
830
  self._source_url: str = "N/A"
827
831
  self._destination_url: str = "N/A"
828
832
 
829
- def get_content_size(self):
833
+ def get_content_size(self) -> int | None:
830
834
  """Content size in bytes.
831
835
 
832
836
  Returns:
833
- Union[int, None]: Content size in bytes or None
837
+ int | None: Content size in bytes or None
834
838
  if is unknown.
835
839
 
836
840
  """
837
841
  return self._content_size
838
842
 
839
- def set_content_size(self, content_size: int):
843
+ def set_content_size(self, content_size: int) -> None:
840
844
  """Set content size in bytes.
841
845
 
842
846
  Args:
@@ -859,7 +863,7 @@ class TransferProgress:
859
863
  """
860
864
  return self._started
861
865
 
862
- def set_started(self):
866
+ def set_started(self) -> None:
863
867
  """Mark that transfer started.
864
868
 
865
869
  Raises:
@@ -890,7 +894,7 @@ class TransferProgress:
890
894
  """
891
895
  return self._transfer_done
892
896
 
893
- def set_transfer_done(self):
897
+ def set_transfer_done(self) -> None:
894
898
  """Mark progress as transfer finished.
895
899
 
896
900
  Raises:
@@ -913,17 +917,17 @@ class TransferProgress:
913
917
  """
914
918
  return self._failed
915
919
 
916
- def get_fail_reason(self) -> Optional[str]:
920
+ def get_fail_reason(self) -> str | None:
917
921
  """Get reason why transfer failed.
918
922
 
919
923
  Returns:
920
- Optional[str]: Reason why transfer
924
+ str | None: Reason why transfer
921
925
  failed or None.
922
926
 
923
927
  """
924
928
  return self._fail_reason
925
929
 
926
- def set_failed(self, reason: str):
930
+ def set_failed(self, reason: str) -> None:
927
931
  """Mark progress as failed.
928
932
 
929
933
  Args:
@@ -942,7 +946,7 @@ class TransferProgress:
942
946
  """
943
947
  return self._transferred
944
948
 
945
- def set_transferred_size(self, transferred: int):
949
+ def set_transferred_size(self, transferred: int) -> None:
946
950
  """Set already transferred size in bytes.
947
951
 
948
952
  Args:
@@ -955,7 +959,7 @@ class TransferProgress:
955
959
  """Reset transferred size to initial value."""
956
960
  self._transferred = 0
957
961
 
958
- def add_transferred_chunk(self, chunk_size: int):
962
+ def add_transferred_chunk(self, chunk_size: int) -> None:
959
963
  """Add transferred chunk size in bytes.
960
964
 
961
965
  Args:
@@ -978,7 +982,7 @@ class TransferProgress:
978
982
  """
979
983
  return self._source_url
980
984
 
981
- def set_source_url(self, url: str):
985
+ def set_source_url(self, url: str) -> None:
982
986
  """Set source url from where transfer happens.
983
987
 
984
988
  Args:
@@ -1000,7 +1004,7 @@ class TransferProgress:
1000
1004
  """
1001
1005
  return self._destination_url
1002
1006
 
1003
- def set_destination_url(self, url: str):
1007
+ def set_destination_url(self, url: str) -> None:
1004
1008
  """Set destination url where transfer happens.
1005
1009
 
1006
1010
  Args:
@@ -1026,11 +1030,11 @@ class TransferProgress:
1026
1030
  return True
1027
1031
 
1028
1032
  @property
1029
- def transfer_progress(self) -> Optional[float]:
1033
+ def transfer_progress(self) -> float | None:
1030
1034
  """Get transfer progress in percents.
1031
1035
 
1032
1036
  Returns:
1033
- Optional[float]: Transfer progress in percents or 'None'
1037
+ float | None: Transfer progress in percents or 'None'
1034
1038
  if content size is unknown.
1035
1039
 
1036
1040
  """
@@ -1049,12 +1053,12 @@ class TransferProgress:
1049
1053
 
1050
1054
 
1051
1055
  def create_dependency_package_basename(
1052
- platform_name: Optional[str] = None
1056
+ platform_name: str | None = None
1053
1057
  ) -> str:
1054
1058
  """Create basename for dependency package file.
1055
1059
 
1056
1060
  Args:
1057
- platform_name (Optional[str]): Name of platform for which the
1061
+ platform_name (str | None): Name of platform for which the
1058
1062
  bundle is targeted. Default value is current platform.
1059
1063
 
1060
1064
  Returns:
@@ -1066,11 +1070,11 @@ def create_dependency_package_basename(
1066
1070
 
1067
1071
  now_date = datetime.datetime.now()
1068
1072
  time_stamp = now_date.strftime("%y%m%d%H%M")
1069
- return "ayon_{}_{}".format(time_stamp, platform_name)
1073
+ return f"ayon_{time_stamp}_{platform_name}"
1070
1074
 
1071
1075
 
1072
1076
 
1073
- def _get_media_mime_type_from_ftyp(content: bytes) -> Optional[str]:
1077
+ def _get_media_mime_type_from_ftyp(content: bytes) -> str | None:
1074
1078
  if content[8:10] == b"qt" or content[8:12] == b"MSNV":
1075
1079
  return "video/quicktime"
1076
1080
 
@@ -1110,7 +1114,7 @@ def _get_media_mime_type_from_ftyp(content: bytes) -> Optional[str]:
1110
1114
  return None
1111
1115
 
1112
1116
 
1113
- def _get_media_mime_type_for_content_base(content: bytes) -> Optional[str]:
1117
+ def _get_media_mime_type_for_content_base(content: bytes) -> str | None:
1114
1118
  """Determine Mime-Type of a file.
1115
1119
 
1116
1120
  Use header of the file to determine mime type (needs 12 bytes).
@@ -1173,14 +1177,14 @@ def _get_media_mime_type_for_content_base(content: bytes) -> Optional[str]:
1173
1177
  return None
1174
1178
 
1175
1179
 
1176
- def _get_svg_mime_type(content: bytes) -> Optional[str]:
1180
+ def _get_svg_mime_type(content: bytes) -> str | None:
1177
1181
  # SVG
1178
1182
  if b'xmlns="http://www.w3.org/2000/svg"' in content:
1179
1183
  return "image/svg+xml"
1180
1184
  return None
1181
1185
 
1182
1186
 
1183
- def _get_json_mime_type(content: bytes) -> Optional[str]:
1187
+ def _get_json_mime_type(content: bytes) -> str | None:
1184
1188
  # json
1185
1189
  try:
1186
1190
  json.loads(content.decode("utf-8"))
@@ -1190,14 +1194,14 @@ def _get_json_mime_type(content: bytes) -> Optional[str]:
1190
1194
  return None
1191
1195
 
1192
1196
 
1193
- def get_media_mime_type_for_content(content: bytes) -> Optional[str]:
1197
+ def get_media_mime_type_for_content(content: bytes) -> str | None:
1194
1198
  mime_type = _get_media_mime_type_for_content_base(content)
1195
1199
  if mime_type is not None:
1196
1200
  return mime_type
1197
1201
  return _get_svg_mime_type(content) or _get_json_mime_type(content)
1198
1202
 
1199
1203
 
1200
- def get_media_mime_type_for_stream(stream: StreamType) -> Optional[str]:
1204
+ def get_media_mime_type_for_stream(stream: StreamType) -> str | None:
1201
1205
  # Read only 12 bytes to determine mime type
1202
1206
  content = stream.read(12)
1203
1207
  mime_type = _get_media_mime_type_for_content_base(content)
@@ -1208,14 +1212,14 @@ def get_media_mime_type_for_stream(stream: StreamType) -> Optional[str]:
1208
1212
  return _get_svg_mime_type(content) or _get_json_mime_type(content)
1209
1213
 
1210
1214
 
1211
- def get_media_mime_type(filepath: str) -> Optional[str]:
1215
+ def get_media_mime_type(filepath: str) -> str | None:
1212
1216
  """Determine Mime-Type of a file.
1213
1217
 
1214
1218
  Args:
1215
1219
  filepath (str): Path to file.
1216
1220
 
1217
1221
  Returns:
1218
- Optional[str]: Mime type or None if is unknown mime type.
1222
+ str | None: Mime type or None if is unknown mime type.
1219
1223
 
1220
1224
  """
1221
1225
  if not filepath or not os.path.exists(filepath):
ayon_api/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  """Package declaring Python API for AYON server."""
2
- __version__ = "1.2.16-dev"
2
+ __version__ = "1.2.17"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ayon_python_api
3
- Version: 1.2.16.dev0
3
+ Version: 1.2.17
4
4
  Summary: AYON Python API
5
5
  Home-page: https://github.com/ynput/ayon-python-api
6
6
  Author: ynput.io