ayon-python-api 0.5.2__tar.gz → 0.5.4__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.5.2 → ayon-python-api-0.5.4}/PKG-INFO +1 -1
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/_api.py +1 -1
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/constants.py +11 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/entity_hub.py +9 -3
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/server_api.py +196 -48
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/utils.py +25 -1
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/version.py +1 -1
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_python_api.egg-info/PKG-INFO +1 -1
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/pyproject.toml +1 -1
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/LICENSE +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/README.md +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/__init__.py +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/events.py +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/exceptions.py +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/graphql.py +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/graphql_queries.py +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_api/operations.py +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_python_api.egg-info/SOURCES.txt +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_python_api.egg-info/dependency_links.txt +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_python_api.egg-info/requires.txt +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/ayon_python_api.egg-info/top_level.txt +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/setup.cfg +0 -0
- {ayon-python-api-0.5.2 → ayon-python-api-0.5.4}/setup.py +0 -0
|
@@ -3,6 +3,10 @@ SERVER_URL_ENV_KEY = "AYON_SERVER_URL"
|
|
|
3
3
|
SERVER_API_ENV_KEY = "AYON_API_KEY"
|
|
4
4
|
SERVER_TIMEOUT_ENV_KEY = "AYON_SERVER_TIMEOUT"
|
|
5
5
|
SERVER_RETRIES_ENV_KEY = "AYON_SERVER_RETRIES"
|
|
6
|
+
# Default variant used for settings
|
|
7
|
+
DEFAULT_VARIANT_ENV_KEY = "AYON_DEFAULT_SETTINGS_VARIANT"
|
|
8
|
+
# Default site id used for connection
|
|
9
|
+
SITE_ID_ENV_KEY = "AYON_SITE_ID"
|
|
6
10
|
|
|
7
11
|
# Backwards compatibility
|
|
8
12
|
SERVER_TOKEN_ENV_KEY = SERVER_API_ENV_KEY
|
|
@@ -40,6 +44,7 @@ DEFAULT_PROJECT_FIELDS = {
|
|
|
40
44
|
"code",
|
|
41
45
|
"config",
|
|
42
46
|
"createdAt",
|
|
47
|
+
"data",
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
# --- Folders ---
|
|
@@ -52,6 +57,7 @@ DEFAULT_FOLDER_FIELDS = {
|
|
|
52
57
|
"parentId",
|
|
53
58
|
"active",
|
|
54
59
|
"thumbnailId",
|
|
60
|
+
"data",
|
|
55
61
|
}
|
|
56
62
|
|
|
57
63
|
# --- Tasks ---
|
|
@@ -63,6 +69,7 @@ DEFAULT_TASK_FIELDS = {
|
|
|
63
69
|
"folderId",
|
|
64
70
|
"active",
|
|
65
71
|
"assignees",
|
|
72
|
+
"data",
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
# --- Products ---
|
|
@@ -72,6 +79,7 @@ DEFAULT_PRODUCT_FIELDS = {
|
|
|
72
79
|
"folderId",
|
|
73
80
|
"active",
|
|
74
81
|
"productType",
|
|
82
|
+
"data",
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
# --- Versions ---
|
|
@@ -86,6 +94,7 @@ DEFAULT_VERSION_FIELDS = {
|
|
|
86
94
|
"thumbnailId",
|
|
87
95
|
"createdAt",
|
|
88
96
|
"updatedAt",
|
|
97
|
+
"data",
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
# --- Representations ---
|
|
@@ -96,6 +105,7 @@ DEFAULT_REPRESENTATION_FIELDS = {
|
|
|
96
105
|
"createdAt",
|
|
97
106
|
"active",
|
|
98
107
|
"versionId",
|
|
108
|
+
"data",
|
|
99
109
|
}
|
|
100
110
|
|
|
101
111
|
REPRESENTATION_FILES_FIELDS = {
|
|
@@ -119,6 +129,7 @@ DEFAULT_WORKFILE_INFO_FIELDS = {
|
|
|
119
129
|
"thumbnailId",
|
|
120
130
|
"updatedAt",
|
|
121
131
|
"updatedBy",
|
|
132
|
+
"data",
|
|
122
133
|
}
|
|
123
134
|
|
|
124
135
|
DEFAULT_EVENT_FIELDS = {
|
|
@@ -36,15 +36,18 @@ class EntityHub(object):
|
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
38
|
def __init__(
|
|
39
|
-
self, project_name, connection=None, allow_data_changes=
|
|
39
|
+
self, project_name, connection=None, allow_data_changes=None
|
|
40
40
|
):
|
|
41
41
|
if not connection:
|
|
42
42
|
connection = get_server_api_connection()
|
|
43
|
-
major, minor,
|
|
43
|
+
major, minor, patch, _, _ = connection.server_version_tuple
|
|
44
44
|
path_start_with_slash = True
|
|
45
45
|
if (major, minor) < (0, 6):
|
|
46
46
|
path_start_with_slash = False
|
|
47
47
|
|
|
48
|
+
if allow_data_changes is None:
|
|
49
|
+
allow_data_changes = connection.graphql_allows_data_in_query
|
|
50
|
+
|
|
48
51
|
self._connection = connection
|
|
49
52
|
self._path_start_with_slash = path_start_with_slash
|
|
50
53
|
|
|
@@ -2546,7 +2549,10 @@ class FolderEntity(BaseEntity):
|
|
|
2546
2549
|
if self.thumbnail_id is not UNKNOWN_VALUE:
|
|
2547
2550
|
output["thumbnailId"] = self.thumbnail_id
|
|
2548
2551
|
|
|
2549
|
-
if
|
|
2552
|
+
if (
|
|
2553
|
+
self._entity_hub.allow_data_changes
|
|
2554
|
+
and self._data is not UNKNOWN_VALUE
|
|
2555
|
+
):
|
|
2550
2556
|
output["data"] = self._data
|
|
2551
2557
|
return output
|
|
2552
2558
|
|
|
@@ -9,6 +9,9 @@ import platform
|
|
|
9
9
|
import copy
|
|
10
10
|
import uuid
|
|
11
11
|
from contextlib import contextmanager
|
|
12
|
+
|
|
13
|
+
import six
|
|
14
|
+
|
|
12
15
|
try:
|
|
13
16
|
from http import HTTPStatus
|
|
14
17
|
except ImportError:
|
|
@@ -27,7 +30,6 @@ except ImportError:
|
|
|
27
30
|
from json import JSONDecodeError as RequestsJSONDecodeError
|
|
28
31
|
|
|
29
32
|
from .constants import (
|
|
30
|
-
SERVER_TIMEOUT_ENV_KEY,
|
|
31
33
|
SERVER_RETRIES_ENV_KEY,
|
|
32
34
|
DEFAULT_PRODUCT_TYPE_FIELDS,
|
|
33
35
|
DEFAULT_PROJECT_FIELDS,
|
|
@@ -76,8 +78,11 @@ from .utils import (
|
|
|
76
78
|
create_dependency_package_basename,
|
|
77
79
|
ThumbnailContent,
|
|
78
80
|
get_default_timeout,
|
|
81
|
+
get_default_settings_variant,
|
|
82
|
+
get_default_site_id,
|
|
79
83
|
)
|
|
80
84
|
|
|
85
|
+
_PLACEHOLDER = object()
|
|
81
86
|
PatternType = type(re.compile(""))
|
|
82
87
|
JSONDecodeError = getattr(json, "JSONDecodeError", ValueError)
|
|
83
88
|
# This should be collected from server schema
|
|
@@ -358,12 +363,16 @@ class ServerAPI(object):
|
|
|
358
363
|
max_retries (Optional[int]): Number of retries for requests.
|
|
359
364
|
"""
|
|
360
365
|
_default_max_retries = 3
|
|
366
|
+
# 1 MB chunk by default
|
|
367
|
+
# TODO find out if these are reasonable default value
|
|
368
|
+
default_download_chunk_size = 1024 * 1024
|
|
369
|
+
default_upload_chunk_size = 1024 * 1024
|
|
361
370
|
|
|
362
371
|
def __init__(
|
|
363
372
|
self,
|
|
364
373
|
base_url,
|
|
365
374
|
token=None,
|
|
366
|
-
site_id=
|
|
375
|
+
site_id=_PLACEHOLDER,
|
|
367
376
|
client_version=None,
|
|
368
377
|
default_settings_variant=None,
|
|
369
378
|
sender=None,
|
|
@@ -382,11 +391,14 @@ class ServerAPI(object):
|
|
|
382
391
|
self._graphql_url = "{}/graphql".format(base_url)
|
|
383
392
|
self._log = None
|
|
384
393
|
self._access_token = token
|
|
394
|
+
# Allow to have 'site_id' to 'None'
|
|
395
|
+
if site_id is _PLACEHOLDER:
|
|
396
|
+
site_id = get_default_site_id()
|
|
385
397
|
self._site_id = site_id
|
|
386
398
|
self._client_version = client_version
|
|
387
399
|
self._default_settings_variant = (
|
|
388
400
|
default_settings_variant
|
|
389
|
-
or
|
|
401
|
+
or get_default_settings_variant()
|
|
390
402
|
)
|
|
391
403
|
self._sender = sender
|
|
392
404
|
|
|
@@ -416,6 +428,8 @@ class ServerAPI(object):
|
|
|
416
428
|
self._server_version = None
|
|
417
429
|
self._server_version_tuple = None
|
|
418
430
|
|
|
431
|
+
self._graphql_allows_data_in_query = None
|
|
432
|
+
|
|
419
433
|
self._session = None
|
|
420
434
|
|
|
421
435
|
self._base_functions_mapping = {
|
|
@@ -941,6 +955,26 @@ class ServerAPI(object):
|
|
|
941
955
|
server_version = property(get_server_version)
|
|
942
956
|
server_version_tuple = property(get_server_version_tuple)
|
|
943
957
|
|
|
958
|
+
@property
|
|
959
|
+
def graphql_allows_data_in_query(self):
|
|
960
|
+
"""GraphlQl query can support 'data' field.
|
|
961
|
+
|
|
962
|
+
This applies only to project hierarchy entities 'project', 'folder',
|
|
963
|
+
'task', 'product', 'version' and 'representation'. Others like 'user'
|
|
964
|
+
still require to use rest api to access 'data'.
|
|
965
|
+
|
|
966
|
+
Returns:
|
|
967
|
+
bool: True if server supports 'data' field in GraphQl query.
|
|
968
|
+
"""
|
|
969
|
+
|
|
970
|
+
if self._graphql_allows_data_in_query is None:
|
|
971
|
+
major, minor, patch, _, _ = self.server_version_tuple
|
|
972
|
+
graphql_allows_data_in_query = True
|
|
973
|
+
if (major, minor, patch) < (0, 5, 5):
|
|
974
|
+
graphql_allows_data_in_query = False
|
|
975
|
+
self._graphql_allows_data_in_query = graphql_allows_data_in_query
|
|
976
|
+
return self._graphql_allows_data_in_query
|
|
977
|
+
|
|
944
978
|
def _get_user_info(self):
|
|
945
979
|
if self._access_token is None:
|
|
946
980
|
return None
|
|
@@ -1566,6 +1600,10 @@ class ServerAPI(object):
|
|
|
1566
1600
|
download happens in thread and other thread want to catch changes over
|
|
1567
1601
|
time.
|
|
1568
1602
|
|
|
1603
|
+
Todos:
|
|
1604
|
+
Use retries and timeout.
|
|
1605
|
+
Return RestApiResponse.
|
|
1606
|
+
|
|
1569
1607
|
Args:
|
|
1570
1608
|
endpoint (str): Endpoint or URL to file that should be downloaded.
|
|
1571
1609
|
filepath (str): Path where file will be downloaded.
|
|
@@ -1576,8 +1614,7 @@ class ServerAPI(object):
|
|
|
1576
1614
|
"""
|
|
1577
1615
|
|
|
1578
1616
|
if not chunk_size:
|
|
1579
|
-
|
|
1580
|
-
chunk_size = 1024 * 1024
|
|
1617
|
+
chunk_size = self.default_download_chunk_size
|
|
1581
1618
|
|
|
1582
1619
|
if endpoint.startswith(self._base_url):
|
|
1583
1620
|
url = endpoint
|
|
@@ -1604,33 +1641,93 @@ class ServerAPI(object):
|
|
|
1604
1641
|
progress.set_transfer_done()
|
|
1605
1642
|
return progress
|
|
1606
1643
|
|
|
1607
|
-
|
|
1644
|
+
@staticmethod
|
|
1645
|
+
def _upload_chunks_iter(file_stream, progress, chunk_size):
|
|
1646
|
+
"""Generator that yields chunks of file.
|
|
1647
|
+
|
|
1648
|
+
Args:
|
|
1649
|
+
file_stream (io.BinaryIO): Byte stream.
|
|
1650
|
+
progress (TransferProgress): Object to track upload progress.
|
|
1651
|
+
chunk_size (int): Size of chunks that are uploaded at once.
|
|
1652
|
+
|
|
1653
|
+
Yields:
|
|
1654
|
+
bytes: Chunk of file.
|
|
1655
|
+
"""
|
|
1656
|
+
|
|
1657
|
+
# Get size of file
|
|
1658
|
+
file_stream.seek(0, io.SEEK_END)
|
|
1659
|
+
size = file_stream.tell()
|
|
1660
|
+
file_stream.seek(0)
|
|
1661
|
+
# Set content size to progress object
|
|
1662
|
+
progress.set_content_size(size)
|
|
1663
|
+
|
|
1664
|
+
while True:
|
|
1665
|
+
chunk = file_stream.read(chunk_size)
|
|
1666
|
+
if not chunk:
|
|
1667
|
+
break
|
|
1668
|
+
progress.add_transferred_chunk(len(chunk))
|
|
1669
|
+
yield chunk
|
|
1670
|
+
|
|
1671
|
+
def _upload_file(
|
|
1672
|
+
self,
|
|
1673
|
+
url,
|
|
1674
|
+
filepath,
|
|
1675
|
+
progress,
|
|
1676
|
+
request_type=None,
|
|
1677
|
+
chunk_size=None,
|
|
1678
|
+
**kwargs
|
|
1679
|
+
):
|
|
1680
|
+
"""
|
|
1681
|
+
|
|
1682
|
+
Args:
|
|
1683
|
+
url (str): Url where file will be uploaded.
|
|
1684
|
+
filepath (str): Source filepath.
|
|
1685
|
+
progress (TransferProgress): Object that gives ability to track
|
|
1686
|
+
progress.
|
|
1687
|
+
request_type (Optional[RequestType]): Type of request that will
|
|
1688
|
+
be used. Default is PUT.
|
|
1689
|
+
chunk_size (Optional[int]): Size of chunks that are uploaded
|
|
1690
|
+
at once.
|
|
1691
|
+
**kwargs (Any): Additional arguments that will be passed
|
|
1692
|
+
to request function.
|
|
1693
|
+
|
|
1694
|
+
Returns:
|
|
1695
|
+
RestApiResponse: Server response.
|
|
1696
|
+
"""
|
|
1697
|
+
|
|
1608
1698
|
if request_type is None:
|
|
1609
1699
|
request_type = RequestTypes.put
|
|
1610
|
-
|
|
1700
|
+
|
|
1611
1701
|
if self._session is None:
|
|
1612
|
-
|
|
1702
|
+
headers = kwargs.setdefault("headers", {})
|
|
1703
|
+
for key, value in self.get_headers().items():
|
|
1704
|
+
if key not in headers:
|
|
1705
|
+
headers[key] = value
|
|
1613
1706
|
post_func = self._base_functions_mapping[request_type]
|
|
1614
1707
|
else:
|
|
1615
1708
|
post_func = self._session_functions_mapping[request_type]
|
|
1616
1709
|
|
|
1710
|
+
if not chunk_size:
|
|
1711
|
+
chunk_size = self.default_upload_chunk_size
|
|
1712
|
+
|
|
1617
1713
|
with open(filepath, "rb") as stream:
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1714
|
+
response = post_func(
|
|
1715
|
+
url,
|
|
1716
|
+
data=self._upload_chunks_iter(stream, progress, chunk_size),
|
|
1717
|
+
**kwargs
|
|
1718
|
+
)
|
|
1719
|
+
|
|
1623
1720
|
response.raise_for_status()
|
|
1624
|
-
progress.set_transferred_size(size)
|
|
1625
1721
|
return response
|
|
1626
1722
|
|
|
1627
1723
|
def upload_file(
|
|
1628
|
-
self, endpoint, filepath, progress=None, request_type=None
|
|
1724
|
+
self, endpoint, filepath, progress=None, request_type=None, **kwargs
|
|
1629
1725
|
):
|
|
1630
1726
|
"""Upload file to server.
|
|
1631
1727
|
|
|
1632
1728
|
Todos:
|
|
1633
|
-
|
|
1729
|
+
Use retries and timeout.
|
|
1730
|
+
Return RestApiResponse.
|
|
1634
1731
|
|
|
1635
1732
|
Args:
|
|
1636
1733
|
endpoint (str): Endpoint or url where file will be uploaded.
|
|
@@ -1639,6 +1736,8 @@ class ServerAPI(object):
|
|
|
1639
1736
|
to track upload progress.
|
|
1640
1737
|
request_type (Optional[RequestType]): Type of request that will
|
|
1641
1738
|
be used to upload file.
|
|
1739
|
+
**kwargs (Any): Additional arguments that will be passed
|
|
1740
|
+
to request function.
|
|
1642
1741
|
|
|
1643
1742
|
Returns:
|
|
1644
1743
|
requests.Response: Response object.
|
|
@@ -1660,7 +1759,9 @@ class ServerAPI(object):
|
|
|
1660
1759
|
progress.set_started()
|
|
1661
1760
|
|
|
1662
1761
|
try:
|
|
1663
|
-
return self._upload_file(
|
|
1762
|
+
return self._upload_file(
|
|
1763
|
+
url, filepath, progress, request_type, **kwargs
|
|
1764
|
+
)
|
|
1664
1765
|
|
|
1665
1766
|
except Exception as exc:
|
|
1666
1767
|
progress.set_failed(str(exc))
|
|
@@ -1883,31 +1984,45 @@ class ServerAPI(object):
|
|
|
1883
1984
|
return set(DEFAULT_EVENT_FIELDS)
|
|
1884
1985
|
|
|
1885
1986
|
if entity_type == "project":
|
|
1886
|
-
entity_type_defaults = DEFAULT_PROJECT_FIELDS
|
|
1987
|
+
entity_type_defaults = set(DEFAULT_PROJECT_FIELDS)
|
|
1988
|
+
if not self.graphql_allows_data_in_query:
|
|
1989
|
+
entity_type_defaults.discard("data")
|
|
1887
1990
|
|
|
1888
1991
|
elif entity_type == "folder":
|
|
1889
|
-
entity_type_defaults = DEFAULT_FOLDER_FIELDS
|
|
1992
|
+
entity_type_defaults = set(DEFAULT_FOLDER_FIELDS)
|
|
1993
|
+
if not self.graphql_allows_data_in_query:
|
|
1994
|
+
entity_type_defaults.discard("data")
|
|
1890
1995
|
|
|
1891
1996
|
elif entity_type == "task":
|
|
1892
|
-
entity_type_defaults = DEFAULT_TASK_FIELDS
|
|
1997
|
+
entity_type_defaults = set(DEFAULT_TASK_FIELDS)
|
|
1998
|
+
if not self.graphql_allows_data_in_query:
|
|
1999
|
+
entity_type_defaults.discard("data")
|
|
1893
2000
|
|
|
1894
2001
|
elif entity_type == "product":
|
|
1895
|
-
entity_type_defaults = DEFAULT_PRODUCT_FIELDS
|
|
2002
|
+
entity_type_defaults = set(DEFAULT_PRODUCT_FIELDS)
|
|
2003
|
+
if not self.graphql_allows_data_in_query:
|
|
2004
|
+
entity_type_defaults.discard("data")
|
|
1896
2005
|
|
|
1897
2006
|
elif entity_type == "version":
|
|
1898
|
-
entity_type_defaults = DEFAULT_VERSION_FIELDS
|
|
2007
|
+
entity_type_defaults = set(DEFAULT_VERSION_FIELDS)
|
|
2008
|
+
if not self.graphql_allows_data_in_query:
|
|
2009
|
+
entity_type_defaults.discard("data")
|
|
1899
2010
|
|
|
1900
2011
|
elif entity_type == "representation":
|
|
1901
2012
|
entity_type_defaults = (
|
|
1902
2013
|
DEFAULT_REPRESENTATION_FIELDS
|
|
1903
2014
|
| REPRESENTATION_FILES_FIELDS
|
|
1904
2015
|
)
|
|
2016
|
+
if not self.graphql_allows_data_in_query:
|
|
2017
|
+
entity_type_defaults.discard("data")
|
|
1905
2018
|
|
|
1906
2019
|
elif entity_type == "productType":
|
|
1907
|
-
entity_type_defaults = DEFAULT_PRODUCT_TYPE_FIELDS
|
|
2020
|
+
entity_type_defaults = set(DEFAULT_PRODUCT_TYPE_FIELDS)
|
|
1908
2021
|
|
|
1909
2022
|
elif entity_type == "workfile":
|
|
1910
|
-
entity_type_defaults = DEFAULT_WORKFILE_INFO_FIELDS
|
|
2023
|
+
entity_type_defaults = set(DEFAULT_WORKFILE_INFO_FIELDS)
|
|
2024
|
+
if not self.graphql_allows_data_in_query:
|
|
2025
|
+
entity_type_defaults.discard("data")
|
|
1911
2026
|
|
|
1912
2027
|
elif entity_type == "user":
|
|
1913
2028
|
entity_type_defaults = set(DEFAULT_USER_FIELDS)
|
|
@@ -3659,7 +3774,7 @@ class ServerAPI(object):
|
|
|
3659
3774
|
fields |= self.get_attributes_fields_for_type("folder")
|
|
3660
3775
|
|
|
3661
3776
|
use_rest = False
|
|
3662
|
-
if "data" in fields:
|
|
3777
|
+
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
3663
3778
|
use_rest = True
|
|
3664
3779
|
fields = {"id"}
|
|
3665
3780
|
|
|
@@ -3680,6 +3795,8 @@ class ServerAPI(object):
|
|
|
3680
3795
|
|
|
3681
3796
|
if use_rest:
|
|
3682
3797
|
folder = self.get_rest_folder(project_name, folder["id"])
|
|
3798
|
+
else:
|
|
3799
|
+
self._convert_entity_data(folder)
|
|
3683
3800
|
|
|
3684
3801
|
if own_attributes:
|
|
3685
3802
|
fill_own_attribs(folder)
|
|
@@ -3897,7 +4014,7 @@ class ServerAPI(object):
|
|
|
3897
4014
|
fields |= self.get_attributes_fields_for_type("task")
|
|
3898
4015
|
|
|
3899
4016
|
use_rest = False
|
|
3900
|
-
if "data" in fields:
|
|
4017
|
+
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
3901
4018
|
use_rest = True
|
|
3902
4019
|
fields = {"id"}
|
|
3903
4020
|
|
|
@@ -3918,6 +4035,8 @@ class ServerAPI(object):
|
|
|
3918
4035
|
|
|
3919
4036
|
if use_rest:
|
|
3920
4037
|
task = self.get_rest_task(project_name, task["id"])
|
|
4038
|
+
else:
|
|
4039
|
+
self._convert_entity_data(task)
|
|
3921
4040
|
|
|
3922
4041
|
if own_attributes:
|
|
3923
4042
|
fill_own_attribs(task)
|
|
@@ -3998,6 +4117,8 @@ class ServerAPI(object):
|
|
|
3998
4117
|
|
|
3999
4118
|
if use_rest:
|
|
4000
4119
|
product = self.get_rest_product(project_name, product["id"])
|
|
4120
|
+
else:
|
|
4121
|
+
self._convert_entity_data(product)
|
|
4001
4122
|
|
|
4002
4123
|
if own_attributes:
|
|
4003
4124
|
fill_own_attribs(product)
|
|
@@ -4104,7 +4225,7 @@ class ServerAPI(object):
|
|
|
4104
4225
|
fields = self.get_default_fields_for_type("product")
|
|
4105
4226
|
|
|
4106
4227
|
use_rest = False
|
|
4107
|
-
if "data" in fields:
|
|
4228
|
+
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
4108
4229
|
use_rest = True
|
|
4109
4230
|
fields = {"id"}
|
|
4110
4231
|
|
|
@@ -4372,7 +4493,7 @@ class ServerAPI(object):
|
|
|
4372
4493
|
fields |= {"id", "version"}
|
|
4373
4494
|
|
|
4374
4495
|
use_rest = False
|
|
4375
|
-
if "data" in fields:
|
|
4496
|
+
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
4376
4497
|
use_rest = True
|
|
4377
4498
|
fields = {"id"}
|
|
4378
4499
|
|
|
@@ -4452,6 +4573,8 @@ class ServerAPI(object):
|
|
|
4452
4573
|
version = self.get_rest_version(
|
|
4453
4574
|
project_name, version["id"]
|
|
4454
4575
|
)
|
|
4576
|
+
else:
|
|
4577
|
+
self._convert_entity_data(version)
|
|
4455
4578
|
|
|
4456
4579
|
if own_attributes:
|
|
4457
4580
|
fill_own_attribs(version)
|
|
@@ -4667,7 +4790,7 @@ class ServerAPI(object):
|
|
|
4667
4790
|
own_attributes=own_attributes
|
|
4668
4791
|
)
|
|
4669
4792
|
return {
|
|
4670
|
-
version["
|
|
4793
|
+
version["productId"]: version
|
|
4671
4794
|
for version in versions
|
|
4672
4795
|
}
|
|
4673
4796
|
|
|
@@ -4781,6 +4904,23 @@ class ServerAPI(object):
|
|
|
4781
4904
|
)
|
|
4782
4905
|
return latest_version["id"] == version_id
|
|
4783
4906
|
|
|
4907
|
+
def _representation_conversion(self, representation):
|
|
4908
|
+
if "context" in representation:
|
|
4909
|
+
orig_context = representation["context"]
|
|
4910
|
+
context = {}
|
|
4911
|
+
if orig_context and orig_context != "null":
|
|
4912
|
+
context = json.loads(orig_context)
|
|
4913
|
+
representation["context"] = context
|
|
4914
|
+
|
|
4915
|
+
repre_files = representation.get("files")
|
|
4916
|
+
if not repre_files:
|
|
4917
|
+
return
|
|
4918
|
+
|
|
4919
|
+
for repre_file in repre_files:
|
|
4920
|
+
repre_file_size = repre_file.get("size")
|
|
4921
|
+
if repre_file_size is not None:
|
|
4922
|
+
repre_file["size"] = int(repre_file["size"])
|
|
4923
|
+
|
|
4784
4924
|
def get_representations(
|
|
4785
4925
|
self,
|
|
4786
4926
|
project_name,
|
|
@@ -4828,10 +4968,12 @@ class ServerAPI(object):
|
|
|
4828
4968
|
fields = set(fields)
|
|
4829
4969
|
if "attrib" in fields:
|
|
4830
4970
|
fields.remove("attrib")
|
|
4831
|
-
fields |= self.get_attributes_fields_for_type(
|
|
4971
|
+
fields |= self.get_attributes_fields_for_type(
|
|
4972
|
+
"representation"
|
|
4973
|
+
)
|
|
4832
4974
|
|
|
4833
4975
|
use_rest = False
|
|
4834
|
-
if "data" in fields:
|
|
4976
|
+
if "data" in fields and not self.graphql_allows_data_in_query:
|
|
4835
4977
|
use_rest = True
|
|
4836
4978
|
fields = {"id"}
|
|
4837
4979
|
|
|
@@ -4894,13 +5036,10 @@ class ServerAPI(object):
|
|
|
4894
5036
|
repre = self.get_rest_representation(
|
|
4895
5037
|
project_name, repre["id"]
|
|
4896
5038
|
)
|
|
5039
|
+
else:
|
|
5040
|
+
self._convert_entity_data(repre)
|
|
4897
5041
|
|
|
4898
|
-
|
|
4899
|
-
orig_context = repre["context"]
|
|
4900
|
-
context = {}
|
|
4901
|
-
if orig_context and orig_context != "null":
|
|
4902
|
-
context = json.loads(orig_context)
|
|
4903
|
-
repre["context"] = context
|
|
5042
|
+
self._representation_conversion(repre)
|
|
4904
5043
|
|
|
4905
5044
|
if own_attributes:
|
|
4906
5045
|
fill_own_attribs(repre)
|
|
@@ -5013,6 +5152,9 @@ class ServerAPI(object):
|
|
|
5013
5152
|
version = repre.pop("version")
|
|
5014
5153
|
product = version.pop("product")
|
|
5015
5154
|
folder = product.pop("folder")
|
|
5155
|
+
self._convert_entity_data(version)
|
|
5156
|
+
self._convert_entity_data(product)
|
|
5157
|
+
self._convert_entity_data(folder)
|
|
5016
5158
|
output[repre_id] = RepresentationParents(
|
|
5017
5159
|
version, product, folder, project
|
|
5018
5160
|
)
|
|
@@ -5465,16 +5607,14 @@ class ServerAPI(object):
|
|
|
5465
5607
|
return thumbnail_id
|
|
5466
5608
|
|
|
5467
5609
|
mime_type = self._get_thumbnail_mime_type(src_filepath)
|
|
5468
|
-
|
|
5469
|
-
content = stream.read()
|
|
5470
|
-
|
|
5471
|
-
response = self.raw_post(
|
|
5610
|
+
response = self.upload_file(
|
|
5472
5611
|
"projects/{}/thumbnails".format(project_name),
|
|
5612
|
+
src_filepath,
|
|
5613
|
+
request_type=RequestTypes.post,
|
|
5473
5614
|
headers={"Content-Type": mime_type},
|
|
5474
|
-
data=content
|
|
5475
5615
|
)
|
|
5476
5616
|
response.raise_for_status()
|
|
5477
|
-
return response.
|
|
5617
|
+
return response.json()["id"]
|
|
5478
5618
|
|
|
5479
5619
|
def update_thumbnail(self, project_name, thumbnail_id, src_filepath):
|
|
5480
5620
|
"""Change thumbnail content by id.
|
|
@@ -5495,13 +5635,11 @@ class ServerAPI(object):
|
|
|
5495
5635
|
raise ValueError("Entered filepath does not exist.")
|
|
5496
5636
|
|
|
5497
5637
|
mime_type = self._get_thumbnail_mime_type(src_filepath)
|
|
5498
|
-
|
|
5499
|
-
content = stream.read()
|
|
5500
|
-
|
|
5501
|
-
response = self.raw_put(
|
|
5638
|
+
response = self.upload_file(
|
|
5502
5639
|
"projects/{}/thumbnails/{}".format(project_name, thumbnail_id),
|
|
5640
|
+
src_filepath,
|
|
5641
|
+
request_type=RequestTypes.put,
|
|
5503
5642
|
headers={"Content-Type": mime_type},
|
|
5504
|
-
data=content
|
|
5505
5643
|
)
|
|
5506
5644
|
response.raise_for_status()
|
|
5507
5645
|
|
|
@@ -6323,3 +6461,13 @@ class ServerAPI(object):
|
|
|
6323
6461
|
op_result["detail"],
|
|
6324
6462
|
))
|
|
6325
6463
|
return op_results
|
|
6464
|
+
|
|
6465
|
+
def _convert_entity_data(self, entity):
|
|
6466
|
+
if not entity:
|
|
6467
|
+
return
|
|
6468
|
+
entity_data = entity.get("data")
|
|
6469
|
+
if (
|
|
6470
|
+
entity_data is not None
|
|
6471
|
+
and isinstance(entity_data, six.string_types)
|
|
6472
|
+
):
|
|
6473
|
+
entity["data"] = json.loads(entity_data)
|
|
@@ -16,7 +16,11 @@ except ImportError:
|
|
|
16
16
|
import requests
|
|
17
17
|
import unidecode
|
|
18
18
|
|
|
19
|
-
from .constants import
|
|
19
|
+
from .constants import (
|
|
20
|
+
SERVER_TIMEOUT_ENV_KEY,
|
|
21
|
+
DEFAULT_VARIANT_ENV_KEY,
|
|
22
|
+
SITE_ID_ENV_KEY,
|
|
23
|
+
)
|
|
20
24
|
from .exceptions import UrlError
|
|
21
25
|
|
|
22
26
|
REMOVED_VALUE = object()
|
|
@@ -46,6 +50,26 @@ def get_default_timeout():
|
|
|
46
50
|
return 10.0
|
|
47
51
|
|
|
48
52
|
|
|
53
|
+
def get_default_settings_variant():
|
|
54
|
+
"""Default settings variant.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
str: Settings variant from environment variable or 'production'.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
return os.environ.get(DEFAULT_VARIANT_ENV_KEY) or "production"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_default_site_id():
|
|
64
|
+
"""Site id used for server connection.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
Union[str, None]: Site id from environment variable or None.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
return os.environ.get(SITE_ID_ENV_KEY)
|
|
71
|
+
|
|
72
|
+
|
|
49
73
|
class ThumbnailContent:
|
|
50
74
|
"""Wrapper for thumbnail content.
|
|
51
75
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Package declaring Python API for Ayon server."""
|
|
2
|
-
__version__ = "0.5.
|
|
2
|
+
__version__ = "0.5.4"
|
|
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.5.2 → ayon-python-api-0.5.4}/ayon_python_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|