Ayon-Python-Api 0.1.9__tar.gz → 0.1.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ayon-python-api-0.1.9/ayon_python_api.egg-info → ayon-python-api-0.1.11}/PKG-INFO +6 -8
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/README.md +6 -8
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/__init__.py +21 -6
- ayon-python-api-0.1.9/ayon_api/server_api.py → ayon-python-api-0.1.11/ayon_api/_api.py +115 -12
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/constants.py +15 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/entity_hub.py +2 -2
- ayon-python-api-0.1.11/ayon_api/events.py +52 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/graphql_queries.py +33 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/operations.py +1 -1
- ayon-python-api-0.1.9/ayon_api/server.py → ayon-python-api-0.1.11/ayon_api/server_api.py +319 -13
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/version.py +1 -1
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11/ayon_python_api.egg-info}/PKG-INFO +6 -8
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_python_api.egg-info/SOURCES.txt +1 -1
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_python_api.egg-info/requires.txt +1 -1
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/pyproject.toml +2 -2
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/setup.py +1 -1
- ayon-python-api-0.1.9/ayon_api/events.py +0 -105
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/LICENSE +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/exceptions.py +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/graphql.py +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/thumbnails.py +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_api/utils.py +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_python_api.egg-info/dependency_links.txt +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_python_api.egg-info/top_level.txt +0 -0
- {ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ayon-python-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: AYON Python API
|
|
5
5
|
Home-page: https://github.com/ynput/ayon-python-api
|
|
6
6
|
Author: ynput.io
|
|
@@ -9,20 +9,18 @@ License: Apache License (2.0)
|
|
|
9
9
|
Description: # AYON server API
|
|
10
10
|
Python client for connection server. Client must be (at least for some time) Python 2 compatible because will be used in DCC that are "older".
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
AYON Python api should support connection to server with raw REST functions and prepared functionality for work with entities. Must not contain only functionality that can be used with core server functionality.
|
|
13
13
|
|
|
14
|
+
Module support singleton connection which is using `AYON_SERVER_URL` and `AYON_TOKEN` environment variables as source for connection. The singleton connection is using `ServerAPI` object. There can be created multiple connection to different server at one time, for that purpose use `ServerAPIBase` object.
|
|
14
15
|
|
|
15
16
|
## TODOs
|
|
16
|
-
-
|
|
17
|
-
- only functions related to v4 should stay at that place and v3 compatible functions should be moved
|
|
18
|
-
- Missing settings getter
|
|
19
|
-
- Missing CRUD operations for entities (Only read is possible)
|
|
20
|
-
- More clear what is difference in `ServerAPIBase` and `ServerAPI`
|
|
17
|
+
- More clear what is difference in `ServerAPIBase` and `ServerAPI` (`server.py` and `server_api.py`) and better names
|
|
21
18
|
- `ServerAPI` was added primarily for desktop app which handle login and logout in a different way so the class should be maybe removed and `ServerAPIBase` should be renamed to `ServerAPI`
|
|
22
19
|
- find more suitable names of classes
|
|
23
|
-
- find more suitable name of objects (right now is used `connection` or `
|
|
20
|
+
- find more suitable name of objects (right now is used `connection` or `con`)
|
|
24
21
|
- Add folder and task changes to operations
|
|
25
22
|
- Entity hub should use operations to update folders and tasks
|
|
23
|
+
|
|
26
24
|
Keywords: AYON,ynput,OpenPype,vfx
|
|
27
25
|
Platform: UNKNOWN
|
|
28
26
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
# AYON server API
|
|
2
2
|
Python client for connection server. Client must be (at least for some time) Python 2 compatible because will be used in DCC that are "older".
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
AYON Python api should support connection to server with raw REST functions and prepared functionality for work with entities. Must not contain only functionality that can be used with core server functionality.
|
|
5
5
|
|
|
6
|
+
Module support singleton connection which is using `AYON_SERVER_URL` and `AYON_TOKEN` environment variables as source for connection. The singleton connection is using `ServerAPI` object. There can be created multiple connection to different server at one time, for that purpose use `ServerAPIBase` object.
|
|
6
7
|
|
|
7
8
|
## TODOs
|
|
8
|
-
-
|
|
9
|
-
- only functions related to v4 should stay at that place and v3 compatible functions should be moved
|
|
10
|
-
- Missing settings getter
|
|
11
|
-
- Missing CRUD operations for entities (Only read is possible)
|
|
12
|
-
- More clear what is difference in `ServerAPIBase` and `ServerAPI`
|
|
9
|
+
- More clear what is difference in `ServerAPIBase` and `ServerAPI` (`server.py` and `server_api.py`) and better names
|
|
13
10
|
- `ServerAPI` was added primarily for desktop app which handle login and logout in a different way so the class should be maybe removed and `ServerAPIBase` should be renamed to `ServerAPI`
|
|
14
11
|
- find more suitable names of classes
|
|
15
|
-
- find more suitable name of objects (right now is used `connection` or `
|
|
12
|
+
- find more suitable name of objects (right now is used `connection` or `con`)
|
|
16
13
|
- Add folder and task changes to operations
|
|
17
|
-
- Entity hub should use operations to update folders and tasks
|
|
14
|
+
- Entity hub should use operations to update folders and tasks
|
|
15
|
+
|
|
@@ -2,21 +2,27 @@ from .utils import (
|
|
|
2
2
|
TransferProgress,
|
|
3
3
|
slugify_string,
|
|
4
4
|
)
|
|
5
|
-
from .server import (
|
|
6
|
-
ServerAPIBase,
|
|
7
|
-
)
|
|
8
|
-
|
|
9
5
|
from .server_api import (
|
|
10
6
|
ServerAPI,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from ._api import (
|
|
10
|
+
GlobalServerAPI,
|
|
11
11
|
ServiceContext,
|
|
12
12
|
|
|
13
13
|
init_service,
|
|
14
|
+
get_service_addon_name,
|
|
15
|
+
get_service_addon_version,
|
|
16
|
+
get_service_addon_settings,
|
|
14
17
|
|
|
15
18
|
is_connection_created,
|
|
19
|
+
create_connection,
|
|
16
20
|
close_connection,
|
|
17
21
|
change_token,
|
|
18
22
|
set_environments,
|
|
19
23
|
get_server_api_connection,
|
|
24
|
+
set_site_id,
|
|
25
|
+
set_client_version,
|
|
20
26
|
|
|
21
27
|
get_base_url,
|
|
22
28
|
get_rest_url,
|
|
@@ -34,6 +40,7 @@ from .server_api import (
|
|
|
34
40
|
delete,
|
|
35
41
|
|
|
36
42
|
get_event,
|
|
43
|
+
get_events,
|
|
37
44
|
dispatch_event,
|
|
38
45
|
update_event,
|
|
39
46
|
enroll_event_job,
|
|
@@ -114,17 +121,24 @@ __all__ = (
|
|
|
114
121
|
"TransferProgress",
|
|
115
122
|
"slugify_string",
|
|
116
123
|
|
|
117
|
-
"ServerAPIBase",
|
|
118
|
-
|
|
119
124
|
"ServerAPI",
|
|
125
|
+
|
|
126
|
+
"GlobalServerAPI",
|
|
120
127
|
"ServiceContext",
|
|
128
|
+
|
|
121
129
|
"init_service",
|
|
130
|
+
"get_service_addon_name",
|
|
131
|
+
"get_service_addon_version",
|
|
132
|
+
"get_service_addon_settings",
|
|
122
133
|
|
|
123
134
|
"is_connection_created",
|
|
135
|
+
"create_connection",
|
|
124
136
|
"close_connection",
|
|
125
137
|
"change_token",
|
|
126
138
|
"set_environments",
|
|
127
139
|
"get_server_api_connection",
|
|
140
|
+
"set_site_id",
|
|
141
|
+
"set_client_version",
|
|
128
142
|
|
|
129
143
|
"get_base_url",
|
|
130
144
|
"get_rest_url",
|
|
@@ -142,6 +156,7 @@ __all__ = (
|
|
|
142
156
|
"delete",
|
|
143
157
|
|
|
144
158
|
"get_event",
|
|
159
|
+
"get_events",
|
|
145
160
|
"dispatch_event",
|
|
146
161
|
"update_event",
|
|
147
162
|
"enroll_event_job",
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"""Singleton based server api for direct access.
|
|
2
|
+
|
|
3
|
+
This implementation will be probably the most used part of package. Gives
|
|
4
|
+
option to have singleton connection to Server URL based on environment variable
|
|
5
|
+
values. All public functions and classes are imported in '__init__.py' so
|
|
6
|
+
they're available directly in top module import.
|
|
7
|
+
"""
|
|
8
|
+
|
|
1
9
|
import os
|
|
2
10
|
import socket
|
|
3
11
|
|
|
@@ -5,11 +13,11 @@ from .constants import (
|
|
|
5
13
|
SERVER_URL_ENV_KEY,
|
|
6
14
|
SERVER_TOKEN_ENV_KEY,
|
|
7
15
|
)
|
|
8
|
-
from .
|
|
16
|
+
from .server_api import ServerAPI
|
|
9
17
|
from .exceptions import FailedServiceInit
|
|
10
18
|
|
|
11
19
|
|
|
12
|
-
class ServerAPI
|
|
20
|
+
class GlobalServerAPI(ServerAPI):
|
|
13
21
|
"""Extended server api which also handles storing tokens and url.
|
|
14
22
|
|
|
15
23
|
Created object expect to have set environment variables
|
|
@@ -17,11 +25,11 @@ class ServerAPI(ServerAPIBase):
|
|
|
17
25
|
but that can be filled afterwards with calling 'login' method.
|
|
18
26
|
"""
|
|
19
27
|
|
|
20
|
-
def __init__(self):
|
|
28
|
+
def __init__(self, site_id=None, client_version=None):
|
|
21
29
|
url = self.get_url()
|
|
22
30
|
token = self.get_token()
|
|
23
31
|
|
|
24
|
-
super(
|
|
32
|
+
super(GlobalServerAPI, self).__init__(url, token, site_id, client_version)
|
|
25
33
|
|
|
26
34
|
self.validate_server_availability()
|
|
27
35
|
self.create_session()
|
|
@@ -34,7 +42,7 @@ class ServerAPI(ServerAPIBase):
|
|
|
34
42
|
"""
|
|
35
43
|
|
|
36
44
|
previous_token = self._access_token
|
|
37
|
-
super(
|
|
45
|
+
super(GlobalServerAPI, self).login(username, password)
|
|
38
46
|
if self.has_valid_token and previous_token != self._access_token:
|
|
39
47
|
os.environ[SERVER_TOKEN_ENV_KEY] = self._access_token
|
|
40
48
|
|
|
@@ -74,7 +82,7 @@ class GlobalContext:
|
|
|
74
82
|
|
|
75
83
|
@classmethod
|
|
76
84
|
def change_token(cls, url, token):
|
|
77
|
-
|
|
85
|
+
GlobalServerAPI.set_environments(url, token)
|
|
78
86
|
if cls._connection is None:
|
|
79
87
|
return
|
|
80
88
|
|
|
@@ -89,10 +97,17 @@ class GlobalContext:
|
|
|
89
97
|
cls._connection.close_session()
|
|
90
98
|
cls._connection = None
|
|
91
99
|
|
|
100
|
+
@classmethod
|
|
101
|
+
def create_connection(cls, *args, **kwargs):
|
|
102
|
+
if cls._connection is not None:
|
|
103
|
+
cls.close_connection()
|
|
104
|
+
cls._connection = GlobalServerAPI(*args, **kwargs)
|
|
105
|
+
return cls._connection
|
|
106
|
+
|
|
92
107
|
@classmethod
|
|
93
108
|
def get_server_api_connection(cls):
|
|
94
109
|
if cls._connection is None:
|
|
95
|
-
cls.
|
|
110
|
+
cls.create_connection()
|
|
96
111
|
return cls._connection
|
|
97
112
|
|
|
98
113
|
|
|
@@ -170,8 +185,8 @@ class ServiceContext:
|
|
|
170
185
|
cls.addon_version = addon_version
|
|
171
186
|
cls.service_name = service_name or socket.gethostname()
|
|
172
187
|
|
|
173
|
-
# Make sure required environments for
|
|
174
|
-
|
|
188
|
+
# Make sure required environments for GlobalServerAPI are set
|
|
189
|
+
GlobalServerAPI.set_environments(cls.server_url, cls.token)
|
|
175
190
|
|
|
176
191
|
if connect:
|
|
177
192
|
print("Connecting to server \"{}\"".format(server_url))
|
|
@@ -181,9 +196,52 @@ class ServiceContext:
|
|
|
181
196
|
|
|
182
197
|
|
|
183
198
|
def init_service(*args, **kwargs):
|
|
199
|
+
"""Initialize current connection from service.
|
|
200
|
+
|
|
201
|
+
The service expect specific environment variables. The variables must all
|
|
202
|
+
be set to make the connection work as a service.
|
|
203
|
+
"""
|
|
204
|
+
|
|
184
205
|
ServiceContext.init_service(*args, **kwargs)
|
|
185
206
|
|
|
186
207
|
|
|
208
|
+
def get_service_addon_name():
|
|
209
|
+
"""Name of addon which initialized service connection.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Union[str, None]: Name of addon or None.
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
return ServiceContext.addon_name
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def get_service_addon_version():
|
|
219
|
+
"""Version of addon which initialized service connection.
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
Union[str, None]: Version of addon or None.
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
return ServiceContext.addon_version
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def get_service_addon_settings():
|
|
229
|
+
"""Addon settings of service which initialized service.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
Dict[str, Any]: Addon settings.
|
|
233
|
+
|
|
234
|
+
Raises:
|
|
235
|
+
ValueError: When service was not initialized.
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
addon_name = get_service_addon_name()
|
|
239
|
+
addon_version = get_service_addon_version()
|
|
240
|
+
if addon_name is None or addon_version is None:
|
|
241
|
+
raise ValueError("Service is not initialized")
|
|
242
|
+
return get_addon_settings(addon_name, addon_version)
|
|
243
|
+
|
|
244
|
+
|
|
187
245
|
def is_connection_created():
|
|
188
246
|
"""Is global connection created.
|
|
189
247
|
|
|
@@ -194,6 +252,20 @@ def is_connection_created():
|
|
|
194
252
|
return GlobalContext.is_connection_created()
|
|
195
253
|
|
|
196
254
|
|
|
255
|
+
def create_connection(site_id=None, client_version=None):
|
|
256
|
+
"""Create global connection.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
site_id (str): Machine site id/name.
|
|
260
|
+
client_version (str): Desktop app version.
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
GlobalServerAPI: Created connection.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
return GlobalContext.create_connection(site_id, client_version)
|
|
267
|
+
|
|
268
|
+
|
|
197
269
|
def close_connection():
|
|
198
270
|
"""Close global connection if is connected."""
|
|
199
271
|
|
|
@@ -221,22 +293,48 @@ def set_environments(url, token):
|
|
|
221
293
|
token (Union[str, None]): API key token to be used for connection.
|
|
222
294
|
"""
|
|
223
295
|
|
|
224
|
-
|
|
296
|
+
GlobalServerAPI.set_environments(url, token)
|
|
225
297
|
|
|
226
298
|
|
|
227
299
|
def get_server_api_connection():
|
|
228
|
-
"""Access to global scope object of
|
|
300
|
+
"""Access to global scope object of GlobalServerAPI.
|
|
229
301
|
|
|
230
302
|
This access expect to have set environment variables 'AYON_SERVER_URL'
|
|
231
303
|
and 'AYON_TOKEN'.
|
|
232
304
|
|
|
233
305
|
Returns:
|
|
234
|
-
|
|
306
|
+
GlobalServerAPI: Object of connection to server.
|
|
235
307
|
"""
|
|
236
308
|
|
|
237
309
|
return GlobalContext.get_server_api_connection()
|
|
238
310
|
|
|
239
311
|
|
|
312
|
+
def set_site_id(site_id):
|
|
313
|
+
"""Set site id of already connected client connection.
|
|
314
|
+
|
|
315
|
+
Site id is human-readable machine id used in AYON desktop application.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
site_id (Union[str, None]): Site id used in connection.
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
con = get_server_api_connection()
|
|
322
|
+
con.set_site_id(site_id)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def set_client_version(client_version):
|
|
326
|
+
"""Set version of already connected client connection.
|
|
327
|
+
|
|
328
|
+
Client version is version of AYON desktop application.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
client_version (Union[str, None]): Client version string.
|
|
332
|
+
"""
|
|
333
|
+
|
|
334
|
+
con = get_server_api_connection()
|
|
335
|
+
con.set_client_version(client_version)
|
|
336
|
+
|
|
337
|
+
|
|
240
338
|
def get_base_url():
|
|
241
339
|
con = get_server_api_connection()
|
|
242
340
|
return con.get_base_url()
|
|
@@ -302,6 +400,11 @@ def get_event(*args, **kwargs):
|
|
|
302
400
|
return con.get_event(*args, **kwargs)
|
|
303
401
|
|
|
304
402
|
|
|
403
|
+
def get_events(*args, **kwargs):
|
|
404
|
+
con = get_server_api_connection()
|
|
405
|
+
return con.get_events(*args, **kwargs)
|
|
406
|
+
|
|
407
|
+
|
|
305
408
|
def dispatch_event(*args, **kwargs):
|
|
306
409
|
con = get_server_api_connection()
|
|
307
410
|
return con.dispatch_event(*args, **kwargs)
|
|
@@ -88,3 +88,18 @@ DEFAULT_WORKFILE_INFO_FIELDS = {
|
|
|
88
88
|
"updatedAt",
|
|
89
89
|
"updatedBy",
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
DEFAULT_EVENT_FIELDS = {
|
|
93
|
+
"id",
|
|
94
|
+
"hash",
|
|
95
|
+
"createdAt",
|
|
96
|
+
"dependsOn",
|
|
97
|
+
"description",
|
|
98
|
+
"project",
|
|
99
|
+
"retries",
|
|
100
|
+
"sender",
|
|
101
|
+
"status",
|
|
102
|
+
"topic",
|
|
103
|
+
"updatedAt",
|
|
104
|
+
"user",
|
|
105
|
+
}
|
|
@@ -3,7 +3,7 @@ import collections
|
|
|
3
3
|
from abc import ABCMeta, abstractmethod, abstractproperty
|
|
4
4
|
|
|
5
5
|
import six
|
|
6
|
-
from .
|
|
6
|
+
from ._api import get_server_api_connection
|
|
7
7
|
from .utils import create_entity_id, convert_entity_id
|
|
8
8
|
|
|
9
9
|
UNKNOWN_VALUE = object()
|
|
@@ -27,7 +27,7 @@ class EntityHub(object):
|
|
|
27
27
|
|
|
28
28
|
Args:
|
|
29
29
|
project_name (str): Name of project where changes will happen.
|
|
30
|
-
connection (
|
|
30
|
+
connection (ServerAPI): Connection to server with logged user.
|
|
31
31
|
allow_data_changes (bool): This option gives ability to change 'data'
|
|
32
32
|
key on entities. This is not recommended as 'data' may be use for
|
|
33
33
|
secure information and would also slow down server queries. Content
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ServerEvent(object):
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
topic,
|
|
8
|
+
sender=None,
|
|
9
|
+
event_hash=None,
|
|
10
|
+
project_name=None,
|
|
11
|
+
username=None,
|
|
12
|
+
dependencies=None,
|
|
13
|
+
description=None,
|
|
14
|
+
summary=None,
|
|
15
|
+
payload=None,
|
|
16
|
+
finished=True,
|
|
17
|
+
store=True,
|
|
18
|
+
):
|
|
19
|
+
if dependencies is None:
|
|
20
|
+
dependencies = []
|
|
21
|
+
if payload is None:
|
|
22
|
+
payload = {}
|
|
23
|
+
if summary is None:
|
|
24
|
+
summary = {}
|
|
25
|
+
|
|
26
|
+
self.topic = topic
|
|
27
|
+
self.sender = sender
|
|
28
|
+
self.event_hash = event_hash
|
|
29
|
+
self.project_name = project_name
|
|
30
|
+
self.username = username
|
|
31
|
+
self.dependencies = dependencies
|
|
32
|
+
self.description = description
|
|
33
|
+
self.summary = summary
|
|
34
|
+
self.payload = payload
|
|
35
|
+
self.finished = finished
|
|
36
|
+
self.store = store
|
|
37
|
+
|
|
38
|
+
def to_data(self):
|
|
39
|
+
return {
|
|
40
|
+
"topic": self.topic,
|
|
41
|
+
"sender": self.sender,
|
|
42
|
+
"hash": self.event_hash,
|
|
43
|
+
"project": self.project_name,
|
|
44
|
+
"user": self.username,
|
|
45
|
+
"dependencies": copy.deepcopy(self.dependencies),
|
|
46
|
+
"description": self.description,
|
|
47
|
+
"description": self.description,
|
|
48
|
+
"summary": copy.deepcopy(self.summary),
|
|
49
|
+
"payload": self.payload,
|
|
50
|
+
"finished": self.finished,
|
|
51
|
+
"store": self.store
|
|
52
|
+
}
|
|
@@ -327,3 +327,36 @@ def workfiles_info_graphql_query(fields):
|
|
|
327
327
|
for k, v in value.items():
|
|
328
328
|
query_queue.append((k, v, field))
|
|
329
329
|
return query
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def events_graphql_query(fields):
|
|
333
|
+
query = GraphQlQuery("WorkfilesInfo")
|
|
334
|
+
topics_var = query.add_variable("eventTopics", "[String!]")
|
|
335
|
+
projects_var = query.add_variable("projectNames", "[String!]")
|
|
336
|
+
states_var = query.add_variable("eventStates", "[String!]")
|
|
337
|
+
users_var = query.add_variable("eventUsers", "[String!]")
|
|
338
|
+
include_logs_var = query.add_variable("includeLogsFilter", "Boolean!")
|
|
339
|
+
|
|
340
|
+
events_field = query.add_field("events", has_edges=True)
|
|
341
|
+
events_field.set_filter("topics", topics_var)
|
|
342
|
+
events_field.set_filter("projects", projects_var)
|
|
343
|
+
events_field.set_filter("states", states_var)
|
|
344
|
+
events_field.set_filter("users", users_var)
|
|
345
|
+
events_field.set_filter("includeLogs", include_logs_var)
|
|
346
|
+
|
|
347
|
+
nested_fields = fields_to_dict(set(fields))
|
|
348
|
+
|
|
349
|
+
query_queue = collections.deque()
|
|
350
|
+
for key, value in nested_fields.items():
|
|
351
|
+
query_queue.append((key, value, events_field))
|
|
352
|
+
|
|
353
|
+
while query_queue:
|
|
354
|
+
item = query_queue.popleft()
|
|
355
|
+
key, value, parent = item
|
|
356
|
+
field = parent.add_field(key)
|
|
357
|
+
if value is FIELD_VALUE:
|
|
358
|
+
continue
|
|
359
|
+
|
|
360
|
+
for k, v in value.items():
|
|
361
|
+
query_queue.append((k, v, field))
|
|
362
|
+
return query
|
|
@@ -6,7 +6,12 @@ import logging
|
|
|
6
6
|
import collections
|
|
7
7
|
import platform
|
|
8
8
|
import copy
|
|
9
|
-
|
|
9
|
+
import uuid
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
try:
|
|
12
|
+
from http import HTTPStatus
|
|
13
|
+
except ImportError:
|
|
14
|
+
HTTPStatus = None
|
|
10
15
|
|
|
11
16
|
import requests
|
|
12
17
|
|
|
@@ -19,6 +24,7 @@ from .constants import (
|
|
|
19
24
|
DEFAULT_REPRESENTATION_FIELDS,
|
|
20
25
|
REPRESENTATION_FILES_FIELDS,
|
|
21
26
|
DEFAULT_WORKFILE_INFO_FIELDS,
|
|
27
|
+
DEFAULT_EVENT_FIELDS,
|
|
22
28
|
)
|
|
23
29
|
from .thumbnails import ThumbnailCache
|
|
24
30
|
from .graphql import GraphQlQuery, INTROSPECTION_QUERY
|
|
@@ -32,6 +38,7 @@ from .graphql_queries import (
|
|
|
32
38
|
representations_graphql_query,
|
|
33
39
|
representations_parents_qraphql_query,
|
|
34
40
|
workfiles_info_graphql_query,
|
|
41
|
+
events_graphql_query,
|
|
35
42
|
)
|
|
36
43
|
from .exceptions import (
|
|
37
44
|
FailedOperations,
|
|
@@ -56,6 +63,12 @@ PROJECT_NAME_REGEX = re.compile(
|
|
|
56
63
|
)
|
|
57
64
|
|
|
58
65
|
|
|
66
|
+
def _get_description(response):
|
|
67
|
+
if HTTPStatus is None:
|
|
68
|
+
return str(response.orig_response)
|
|
69
|
+
return HTTPStatus(response.status).description
|
|
70
|
+
|
|
71
|
+
|
|
59
72
|
class RequestType:
|
|
60
73
|
def __init__(self, name):
|
|
61
74
|
self.name = name
|
|
@@ -95,7 +108,10 @@ class RestApiResponse(object):
|
|
|
95
108
|
@property
|
|
96
109
|
def data(self):
|
|
97
110
|
if self._data is None:
|
|
98
|
-
self.
|
|
111
|
+
if self.status != 204:
|
|
112
|
+
self._data = self.orig_response.json()
|
|
113
|
+
else:
|
|
114
|
+
self._data = {}
|
|
99
115
|
return self._data
|
|
100
116
|
|
|
101
117
|
@property
|
|
@@ -108,7 +124,7 @@ class RestApiResponse(object):
|
|
|
108
124
|
|
|
109
125
|
@property
|
|
110
126
|
def detail(self):
|
|
111
|
-
return self.get("detail",
|
|
127
|
+
return self.get("detail", _get_description(self))
|
|
112
128
|
|
|
113
129
|
@property
|
|
114
130
|
def status_code(self):
|
|
@@ -172,7 +188,91 @@ def fill_own_attribs(entity):
|
|
|
172
188
|
own_attrib[key] = copy.deepcopy(value)
|
|
173
189
|
|
|
174
190
|
|
|
175
|
-
class
|
|
191
|
+
class _AsUserStack:
|
|
192
|
+
"""Handle stack of users used over server api connection in service mode.
|
|
193
|
+
|
|
194
|
+
ServerAPI can behave as other users if it is using special API key.
|
|
195
|
+
|
|
196
|
+
Examples:
|
|
197
|
+
>>> stack = _AsUserStack()
|
|
198
|
+
>>> stack.set_default_username("DefaultName")
|
|
199
|
+
>>> print(stack.username)
|
|
200
|
+
DefaultName
|
|
201
|
+
>>> with stack.as_user("Other1"):
|
|
202
|
+
... print(stack.username)
|
|
203
|
+
... with stack.as_user("Other2"):
|
|
204
|
+
... print(stack.username)
|
|
205
|
+
... print(stack.username)
|
|
206
|
+
... stack.clear()
|
|
207
|
+
... print(stack.username)
|
|
208
|
+
Other1
|
|
209
|
+
Other2
|
|
210
|
+
Other1
|
|
211
|
+
None
|
|
212
|
+
>>> print(stack.username)
|
|
213
|
+
None
|
|
214
|
+
>>> stack.set_default_username("DefaultName")
|
|
215
|
+
>>> print(stack.username)
|
|
216
|
+
DefaultName
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
def __init__(self):
|
|
220
|
+
self._users_by_id = {}
|
|
221
|
+
self._user_ids = []
|
|
222
|
+
self._last_user = None
|
|
223
|
+
self._default_user = None
|
|
224
|
+
|
|
225
|
+
def clear(self):
|
|
226
|
+
self._users_by_id = {}
|
|
227
|
+
self._user_ids = []
|
|
228
|
+
self._last_user = None
|
|
229
|
+
self._default_user = None
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def username(self):
|
|
233
|
+
# Use '_user_ids' for boolean check to have ability "unset"
|
|
234
|
+
# default user
|
|
235
|
+
if self._user_ids:
|
|
236
|
+
return self._last_user
|
|
237
|
+
return self._default_user
|
|
238
|
+
|
|
239
|
+
def get_default_username(self):
|
|
240
|
+
return self._default_user
|
|
241
|
+
|
|
242
|
+
def set_default_username(self, username=None):
|
|
243
|
+
self._default_user = username
|
|
244
|
+
|
|
245
|
+
default_username = property(get_default_username, set_default_username)
|
|
246
|
+
|
|
247
|
+
@contextmanager
|
|
248
|
+
def as_user(self, username):
|
|
249
|
+
self._last_user = username
|
|
250
|
+
user_id = uuid.uuid4().hex
|
|
251
|
+
self._user_ids.append(user_id)
|
|
252
|
+
self._users_by_id[user_id] = username
|
|
253
|
+
try:
|
|
254
|
+
yield
|
|
255
|
+
finally:
|
|
256
|
+
self._users_by_id.pop(user_id, None)
|
|
257
|
+
if not self._user_ids:
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
# First check if is the user id the last one
|
|
261
|
+
was_last = self._user_ids[-1] == user_id
|
|
262
|
+
# Remove id from variables
|
|
263
|
+
if user_id in self._user_ids:
|
|
264
|
+
self._user_ids.remove(user_id)
|
|
265
|
+
|
|
266
|
+
if not was_last:
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
new_last_user = None
|
|
270
|
+
if self._user_ids:
|
|
271
|
+
new_last_user = self._users_by_id.get(self._user_ids[-1])
|
|
272
|
+
self._last_user = new_last_user
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class ServerAPI(object):
|
|
176
276
|
"""Base handler of connection to server.
|
|
177
277
|
|
|
178
278
|
Requires url to server which is used as base for api and graphql calls.
|
|
@@ -225,8 +325,15 @@ class ServerAPIBase(object):
|
|
|
225
325
|
self._attributes_schema = None
|
|
226
326
|
self._entity_type_attributes_cache = {}
|
|
227
327
|
|
|
328
|
+
self._as_user_stack = _AsUserStack()
|
|
228
329
|
self._thumbnail_cache = ThumbnailCache(True)
|
|
229
330
|
|
|
331
|
+
@property
|
|
332
|
+
def log(self):
|
|
333
|
+
if self._log is None:
|
|
334
|
+
self._log = logging.getLogger(self.__class__.__name__)
|
|
335
|
+
return self._log
|
|
336
|
+
|
|
230
337
|
def get_base_url(self):
|
|
231
338
|
return self._base_url
|
|
232
339
|
|
|
@@ -248,12 +355,111 @@ class ServerAPIBase(object):
|
|
|
248
355
|
return
|
|
249
356
|
self._site_id = site_id
|
|
250
357
|
# Recreate session on machine id change
|
|
251
|
-
|
|
252
|
-
self.close_session()
|
|
253
|
-
self.create_session()
|
|
358
|
+
self._update_session_headers()
|
|
254
359
|
|
|
255
360
|
site_id = property(get_site_id, set_site_id)
|
|
256
361
|
|
|
362
|
+
def get_client_version(self):
|
|
363
|
+
"""Version of client used to connect to server.
|
|
364
|
+
|
|
365
|
+
Client version is AYON client build desktop application.
|
|
366
|
+
|
|
367
|
+
Returns:
|
|
368
|
+
str: Client version string used in connection.
|
|
369
|
+
"""
|
|
370
|
+
|
|
371
|
+
return self._client_version
|
|
372
|
+
|
|
373
|
+
def set_client_version(self, client_version):
|
|
374
|
+
"""Set version of client used to connect to server.
|
|
375
|
+
|
|
376
|
+
Client version is AYON client build desktop application.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
client_version (Union[str, None]): Client version string.
|
|
380
|
+
"""
|
|
381
|
+
|
|
382
|
+
if self._client_version == client_version:
|
|
383
|
+
return
|
|
384
|
+
|
|
385
|
+
self._client_version = client_version
|
|
386
|
+
self._update_session_headers()
|
|
387
|
+
|
|
388
|
+
client_version = property(get_client_version, set_client_version)
|
|
389
|
+
|
|
390
|
+
def get_default_service_username(self):
|
|
391
|
+
"""Default username used for callbacks when used with service API key.
|
|
392
|
+
|
|
393
|
+
Returns:
|
|
394
|
+
Union[str, None]: Username if any was filled.
|
|
395
|
+
"""
|
|
396
|
+
|
|
397
|
+
return self._as_user_stack.get_default_username()
|
|
398
|
+
|
|
399
|
+
def set_default_service_username(self, username=None):
|
|
400
|
+
"""Service API will work as other user.
|
|
401
|
+
|
|
402
|
+
Service API keys can work as other user. It can be temporary using
|
|
403
|
+
context manager 'as_user' or it is possible to set default username if
|
|
404
|
+
'as_user' context manager is not entered.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
username (Union[str, None]): Username to work as when service.
|
|
408
|
+
|
|
409
|
+
Raises:
|
|
410
|
+
ValueError: When connection is not yet authenticated or api key
|
|
411
|
+
is not service token.
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
current_username = self._as_user_stack.get_default_username()
|
|
415
|
+
if current_username == username:
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
if not self.has_valid_token:
|
|
419
|
+
raise ValueError(
|
|
420
|
+
"Authentication of connection did not happen yet."
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if not self._access_token_is_service:
|
|
424
|
+
raise ValueError(
|
|
425
|
+
"Can't set service username. API key is not a service token."
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
self._as_user_stack.set_default_username(username)
|
|
429
|
+
if self._as_user_stack.username == username:
|
|
430
|
+
self._update_session_headers()
|
|
431
|
+
|
|
432
|
+
@contextmanager
|
|
433
|
+
def as_username(self, username):
|
|
434
|
+
"""Service API will temporarily work as other user.
|
|
435
|
+
|
|
436
|
+
This method can be used only if service API key is logged in.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
username (Union[str, None]): Username to work as when service.
|
|
440
|
+
|
|
441
|
+
Raises:
|
|
442
|
+
ValueError: When connection is not yet authenticated or api key
|
|
443
|
+
is not service token.
|
|
444
|
+
"""
|
|
445
|
+
|
|
446
|
+
if not self.has_valid_token:
|
|
447
|
+
raise ValueError(
|
|
448
|
+
"Authentication of connection did not happen yet."
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
if not self._access_token_is_service:
|
|
452
|
+
raise ValueError(
|
|
453
|
+
"Can't set service username. API key is not a service token."
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
with self._as_user_stack.as_user(username) as o:
|
|
457
|
+
self._update_session_headers()
|
|
458
|
+
try:
|
|
459
|
+
yield o
|
|
460
|
+
finally:
|
|
461
|
+
self._update_session_headers()
|
|
462
|
+
|
|
257
463
|
@property
|
|
258
464
|
def is_server_available(self):
|
|
259
465
|
if self._server_available is None:
|
|
@@ -303,6 +509,7 @@ class ServerAPIBase(object):
|
|
|
303
509
|
if self._session is not None:
|
|
304
510
|
raise ValueError("Session is already created.")
|
|
305
511
|
|
|
512
|
+
self._as_user_stack.clear()
|
|
306
513
|
# Validate token before session creation
|
|
307
514
|
self.validate_token()
|
|
308
515
|
|
|
@@ -327,6 +534,21 @@ class ServerAPIBase(object):
|
|
|
327
534
|
self._session_functions_mapping = {}
|
|
328
535
|
session.close()
|
|
329
536
|
|
|
537
|
+
def _update_session_headers(self):
|
|
538
|
+
if self._session is None:
|
|
539
|
+
return
|
|
540
|
+
|
|
541
|
+
# Header keys that may change over time
|
|
542
|
+
for key, value in (
|
|
543
|
+
("X-as-user", self._as_user_stack.username),
|
|
544
|
+
("x-ayon-version", self._client_version),
|
|
545
|
+
("x-ayon-site-id", self._site_id),
|
|
546
|
+
):
|
|
547
|
+
if value is not None:
|
|
548
|
+
self._session.headers[key] = value
|
|
549
|
+
elif key in self._session.headers:
|
|
550
|
+
self._session.headers.pop(key)
|
|
551
|
+
|
|
330
552
|
def get_info(self):
|
|
331
553
|
"""Get information about current used api key.
|
|
332
554
|
|
|
@@ -383,12 +605,6 @@ class ServerAPIBase(object):
|
|
|
383
605
|
raise UnauthorizedError("User is not authorized.")
|
|
384
606
|
return output
|
|
385
607
|
|
|
386
|
-
@property
|
|
387
|
-
def log(self):
|
|
388
|
-
if self._log is None:
|
|
389
|
-
self._log = logging.getLogger(self.__class__.__name__)
|
|
390
|
-
return self._log
|
|
391
|
-
|
|
392
608
|
def get_headers(self, content_type=None):
|
|
393
609
|
if content_type is None:
|
|
394
610
|
content_type = "application/json"
|
|
@@ -407,6 +623,9 @@ class ServerAPIBase(object):
|
|
|
407
623
|
if self._access_token:
|
|
408
624
|
if self._access_token_is_service:
|
|
409
625
|
headers["X-Api-Key"] = self._access_token
|
|
626
|
+
username = self._as_user_stack.username
|
|
627
|
+
if username:
|
|
628
|
+
headers["X-as-user"] = username
|
|
410
629
|
else:
|
|
411
630
|
headers["Authorization"] = "Bearer {}".format(
|
|
412
631
|
self._access_token)
|
|
@@ -586,6 +805,74 @@ class ServerAPIBase(object):
|
|
|
586
805
|
response.raise_for_status()
|
|
587
806
|
return response.data
|
|
588
807
|
|
|
808
|
+
def get_events(
|
|
809
|
+
self,
|
|
810
|
+
topics=None,
|
|
811
|
+
project_names=None,
|
|
812
|
+
states=None,
|
|
813
|
+
users=None,
|
|
814
|
+
include_logs=None,
|
|
815
|
+
fields=None
|
|
816
|
+
):
|
|
817
|
+
"""Get events from server with filtering options.
|
|
818
|
+
|
|
819
|
+
Notes:
|
|
820
|
+
Not all event happen on a project.
|
|
821
|
+
|
|
822
|
+
Args:
|
|
823
|
+
topics (Iterable[str]): Name of topics.
|
|
824
|
+
project_names (Iterable[str]): Project on which event happened.
|
|
825
|
+
states (Iterable[str]): Filtering by states.
|
|
826
|
+
users (Iterable[str]): Filtering by users who created/triggered
|
|
827
|
+
an event.
|
|
828
|
+
include_logs (bool): Query also log events.
|
|
829
|
+
fields (Iterable[str]): Fields that should be received for each
|
|
830
|
+
event.
|
|
831
|
+
|
|
832
|
+
Returns:
|
|
833
|
+
Generator[Dict[str, Any]]: Available events matching filters.
|
|
834
|
+
"""
|
|
835
|
+
|
|
836
|
+
filters = {}
|
|
837
|
+
if topics is not None:
|
|
838
|
+
topics = set(topics)
|
|
839
|
+
if not topics:
|
|
840
|
+
return
|
|
841
|
+
filters["eventTopics"] = list(topics)
|
|
842
|
+
|
|
843
|
+
if project_names is not None:
|
|
844
|
+
project_names = set(project_names)
|
|
845
|
+
if not project_names:
|
|
846
|
+
return
|
|
847
|
+
filters["projectName"] = list(project_names)
|
|
848
|
+
|
|
849
|
+
if states is not None:
|
|
850
|
+
states = set(states)
|
|
851
|
+
if not states:
|
|
852
|
+
return
|
|
853
|
+
filters["eventStates"] = list(states)
|
|
854
|
+
|
|
855
|
+
if users is not None:
|
|
856
|
+
users = set(users)
|
|
857
|
+
if not users:
|
|
858
|
+
return
|
|
859
|
+
filters["eventUsers"] = list(users)
|
|
860
|
+
|
|
861
|
+
if include_logs is None:
|
|
862
|
+
include_logs = False
|
|
863
|
+
filters["includeLogsFilter"] = include_logs
|
|
864
|
+
|
|
865
|
+
if not fields:
|
|
866
|
+
fields = DEFAULT_EVENT_FIELDS
|
|
867
|
+
|
|
868
|
+
query = events_graphql_query(set(fields))
|
|
869
|
+
for attr, filter_value in filters.items():
|
|
870
|
+
query.set_variable_value(attr, filter_value)
|
|
871
|
+
|
|
872
|
+
for parsed_data in query.continuous_query(self):
|
|
873
|
+
for event in parsed_data["events"]:
|
|
874
|
+
yield event
|
|
875
|
+
|
|
589
876
|
def update_event(
|
|
590
877
|
self,
|
|
591
878
|
event_id,
|
|
@@ -627,6 +914,25 @@ class ServerAPIBase(object):
|
|
|
627
914
|
finished=True,
|
|
628
915
|
store=True,
|
|
629
916
|
):
|
|
917
|
+
"""Dispatch event to server.
|
|
918
|
+
|
|
919
|
+
Arg:
|
|
920
|
+
topic (str): Event topic used for filtering of listeners.
|
|
921
|
+
sender (Optional[str]): Sender of event.
|
|
922
|
+
hash (Optional[str]): Event hash.
|
|
923
|
+
project_name (Optional[str]): Project name.
|
|
924
|
+
username (Optional[str]): Username which triggered event.
|
|
925
|
+
dependencies (Optional[list[str]]): List of event id deprendencies.
|
|
926
|
+
description (Optional[str]): Description of event.
|
|
927
|
+
summary (Optional[dict[str, Any]]): Summary of event that can be used
|
|
928
|
+
for simple filtering on listeners.
|
|
929
|
+
payload (Optional[dict[str, Any]]): Full payload of event data with
|
|
930
|
+
all details.
|
|
931
|
+
finished (bool): Mark event as finished on dispatch.
|
|
932
|
+
store (bool): Store event in event queue for possible future processing
|
|
933
|
+
otherwise is event send only to active listeners.
|
|
934
|
+
"""
|
|
935
|
+
|
|
630
936
|
if summary is None:
|
|
631
937
|
summary = {}
|
|
632
938
|
if payload is None:
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Package declaring Python API for Ayon server."""
|
|
2
|
-
__version__ = "0.1.
|
|
2
|
+
__version__ = "0.1.11"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ayon-python-api
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: AYON Python API
|
|
5
5
|
Home-page: https://github.com/ynput/ayon-python-api
|
|
6
6
|
Author: ynput.io
|
|
@@ -9,20 +9,18 @@ License: Apache License (2.0)
|
|
|
9
9
|
Description: # AYON server API
|
|
10
10
|
Python client for connection server. Client must be (at least for some time) Python 2 compatible because will be used in DCC that are "older".
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
AYON Python api should support connection to server with raw REST functions and prepared functionality for work with entities. Must not contain only functionality that can be used with core server functionality.
|
|
13
13
|
|
|
14
|
+
Module support singleton connection which is using `AYON_SERVER_URL` and `AYON_TOKEN` environment variables as source for connection. The singleton connection is using `ServerAPI` object. There can be created multiple connection to different server at one time, for that purpose use `ServerAPIBase` object.
|
|
14
15
|
|
|
15
16
|
## TODOs
|
|
16
|
-
-
|
|
17
|
-
- only functions related to v4 should stay at that place and v3 compatible functions should be moved
|
|
18
|
-
- Missing settings getter
|
|
19
|
-
- Missing CRUD operations for entities (Only read is possible)
|
|
20
|
-
- More clear what is difference in `ServerAPIBase` and `ServerAPI`
|
|
17
|
+
- More clear what is difference in `ServerAPIBase` and `ServerAPI` (`server.py` and `server_api.py`) and better names
|
|
21
18
|
- `ServerAPI` was added primarily for desktop app which handle login and logout in a different way so the class should be maybe removed and `ServerAPIBase` should be renamed to `ServerAPI`
|
|
22
19
|
- find more suitable names of classes
|
|
23
|
-
- find more suitable name of objects (right now is used `connection` or `
|
|
20
|
+
- find more suitable name of objects (right now is used `connection` or `con`)
|
|
24
21
|
- Add folder and task changes to operations
|
|
25
22
|
- Entity hub should use operations to update folders and tasks
|
|
23
|
+
|
|
26
24
|
Keywords: AYON,ynput,OpenPype,vfx
|
|
27
25
|
Platform: UNKNOWN
|
|
28
26
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -3,6 +3,7 @@ README.md
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
setup.py
|
|
5
5
|
ayon_api/__init__.py
|
|
6
|
+
ayon_api/_api.py
|
|
6
7
|
ayon_api/constants.py
|
|
7
8
|
ayon_api/entity_hub.py
|
|
8
9
|
ayon_api/events.py
|
|
@@ -10,7 +11,6 @@ ayon_api/exceptions.py
|
|
|
10
11
|
ayon_api/graphql.py
|
|
11
12
|
ayon_api/graphql_queries.py
|
|
12
13
|
ayon_api/operations.py
|
|
13
|
-
ayon_api/server.py
|
|
14
14
|
ayon_api/server_api.py
|
|
15
15
|
ayon_api/thumbnails.py
|
|
16
16
|
ayon_api/utils.py
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "ayon_api"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.11"
|
|
4
4
|
description = "Python api for AYON server"
|
|
5
5
|
authors = ["ynput.io <info@ynput.io>"]
|
|
6
6
|
|
|
7
7
|
[tool.poetry.dependencies]
|
|
8
8
|
requests = "^2.28.1"
|
|
9
9
|
six = "^1.15"
|
|
10
|
-
Unidecode = "^1.
|
|
10
|
+
Unidecode = "^1.2"
|
|
11
11
|
appdirs = "^1.4"
|
|
12
12
|
|
|
13
13
|
[tool.poetry.dev-dependencies]
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import copy
|
|
2
|
-
|
|
3
|
-
from .server_api import get_server_api_connection
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class ServerEvent(object):
|
|
7
|
-
def __init__(
|
|
8
|
-
self,
|
|
9
|
-
topic,
|
|
10
|
-
sender=None,
|
|
11
|
-
hash=None,
|
|
12
|
-
project_name=None,
|
|
13
|
-
username=None,
|
|
14
|
-
dependencies=None,
|
|
15
|
-
description=None,
|
|
16
|
-
summary=None,
|
|
17
|
-
payload=None,
|
|
18
|
-
finished=True,
|
|
19
|
-
store=True,
|
|
20
|
-
):
|
|
21
|
-
if dependencies is None:
|
|
22
|
-
dependencies = []
|
|
23
|
-
if payload is None:
|
|
24
|
-
payload = {}
|
|
25
|
-
if summary is None:
|
|
26
|
-
summary = {}
|
|
27
|
-
|
|
28
|
-
self.topic = topic
|
|
29
|
-
self.sender = sender
|
|
30
|
-
self.hash = hash
|
|
31
|
-
self.project_name = project_name
|
|
32
|
-
self.username = username
|
|
33
|
-
self.dependencies = dependencies
|
|
34
|
-
self.summary = summary
|
|
35
|
-
self.payload = payload
|
|
36
|
-
self.finished = finished
|
|
37
|
-
self.store = store
|
|
38
|
-
|
|
39
|
-
def to_data(self):
|
|
40
|
-
return {
|
|
41
|
-
"topic": self.topic,
|
|
42
|
-
"sender": self.sender,
|
|
43
|
-
"hash": self.hash,
|
|
44
|
-
"project": self.project_name,
|
|
45
|
-
"user": self.username,
|
|
46
|
-
"dependencies": copy.deepcopy(self.dependencies),
|
|
47
|
-
"description": self.description,
|
|
48
|
-
"summary": copy.deepcopy(self.summary),
|
|
49
|
-
"payload": self.payload,
|
|
50
|
-
"finished": self.finished,
|
|
51
|
-
"store": self.store
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def dispatch_event(
|
|
56
|
-
topic,
|
|
57
|
-
sender=None,
|
|
58
|
-
hash=None,
|
|
59
|
-
project_name=None,
|
|
60
|
-
username=None,
|
|
61
|
-
dependencies=None,
|
|
62
|
-
description=None,
|
|
63
|
-
summary=None,
|
|
64
|
-
payload=None,
|
|
65
|
-
finished=True,
|
|
66
|
-
store=True,
|
|
67
|
-
):
|
|
68
|
-
"""Dispatch event to server.
|
|
69
|
-
|
|
70
|
-
Arg:
|
|
71
|
-
topic (str): Event topic used for filtering of listeners.
|
|
72
|
-
sender (Optional[str]): Sender of event.
|
|
73
|
-
hash (Optional[str]): Event hash.
|
|
74
|
-
project_name (Optional[str]): Project name.
|
|
75
|
-
username (Optional[str]): Username which triggered event.
|
|
76
|
-
dependencies (Optional[list[str]]): List of event id deprendencies.
|
|
77
|
-
description (Optional[str]): Description of event.
|
|
78
|
-
summary (Optional[dict[str, Any]]): Summary of event that can be used
|
|
79
|
-
for simple filtering on listeners.
|
|
80
|
-
payload (Optional[dict[str, Any]]): Full payload of event data with
|
|
81
|
-
all details.
|
|
82
|
-
finished (bool): Mark event as finished on dispatch.
|
|
83
|
-
store (bool): Store event in event queue for possible future processing
|
|
84
|
-
otherwise is event send only to active listeners.
|
|
85
|
-
"""
|
|
86
|
-
|
|
87
|
-
event = ServerEvent(
|
|
88
|
-
topic,
|
|
89
|
-
sender,
|
|
90
|
-
hash,
|
|
91
|
-
project_name,
|
|
92
|
-
username,
|
|
93
|
-
dependencies,
|
|
94
|
-
description,
|
|
95
|
-
summary,
|
|
96
|
-
payload,
|
|
97
|
-
finished,
|
|
98
|
-
store
|
|
99
|
-
)
|
|
100
|
-
con = get_server_api_connection()
|
|
101
|
-
response = con.post("events", json=event.to_data())
|
|
102
|
-
if response:
|
|
103
|
-
print(response, response.data)
|
|
104
|
-
return event
|
|
105
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ayon-python-api-0.1.9 → ayon-python-api-0.1.11}/ayon_python_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|