Ayon-Python-Api 0.1.14__tar.gz → 0.1.16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. ayon-python-api-0.1.16/PKG-INFO +72 -0
  2. ayon-python-api-0.1.16/README.md +56 -0
  3. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/entity_hub.py +19 -3
  4. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/operations.py +18 -151
  5. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/server_api.py +682 -59
  6. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/utils.py +6 -0
  7. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/version.py +1 -1
  8. ayon-python-api-0.1.16/ayon_python_api.egg-info/PKG-INFO +72 -0
  9. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/pyproject.toml +1 -1
  10. ayon-python-api-0.1.14/PKG-INFO +0 -31
  11. ayon-python-api-0.1.14/README.md +0 -15
  12. ayon-python-api-0.1.14/ayon_python_api.egg-info/PKG-INFO +0 -31
  13. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/LICENSE +0 -0
  14. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/__init__.py +0 -0
  15. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/_api.py +0 -0
  16. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/constants.py +0 -0
  17. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/events.py +0 -0
  18. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/exceptions.py +0 -0
  19. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/graphql.py +0 -0
  20. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/graphql_queries.py +0 -0
  21. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_api/thumbnails.py +0 -0
  22. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_python_api.egg-info/SOURCES.txt +0 -0
  23. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_python_api.egg-info/dependency_links.txt +0 -0
  24. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_python_api.egg-info/requires.txt +0 -0
  25. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/ayon_python_api.egg-info/top_level.txt +0 -0
  26. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/setup.cfg +0 -0
  27. {ayon-python-api-0.1.14 → ayon-python-api-0.1.16}/setup.py +0 -0
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.1
2
+ Name: ayon-python-api
3
+ Version: 0.1.16
4
+ Summary: AYON Python API
5
+ Home-page: https://github.com/ynput/ayon-python-api
6
+ Author: ynput.io
7
+ Author-email: info@ynput.io
8
+ License: Apache License (2.0)
9
+ Keywords: AYON,ynput,OpenPype,vfx
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 2
13
+ Classifier: Programming Language :: Python :: 3
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+
17
+ # AYON server API
18
+ 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".
19
+
20
+ 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.
21
+
22
+ 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.
23
+
24
+ ## Install
25
+ AYON python api is available on PyPi:
26
+
27
+ pip install ayon-python-api
28
+
29
+ For development purposes you may follow [build](#build-wheel) guide to build and install custom wheels.
30
+
31
+
32
+ ## Cloning the repository
33
+ Repository does not have submodules or special cases. Clone is simple as:
34
+
35
+ git clone git@github.com:ynput/ayon-python-api.git
36
+
37
+
38
+ ## Build wheel
39
+ For wheel build is required a `wheel` module from PyPi:
40
+
41
+ pip install wheel
42
+
43
+ Open terminal and change directory to ayon-python-api repository and build wheel:
44
+
45
+ cd <REPOSITORY ROOT>/ayon-python-api
46
+ python setup.py sdist bdist_wheel
47
+
48
+
49
+ Once finished a wheel should be created in `./dist/ayon_python_api-<VERSION>-py3-none-any`.
50
+
51
+ ---
52
+
53
+ ### Wheel installation
54
+ The wheel file can be used to install using pip:
55
+
56
+ pip install <REPOSITORY ROOT>/dist/ayon_python_api-<VERSION>-py3-none-any
57
+
58
+ If pip complain that `ayon-python-api` is already installed just uninstall existing one first:
59
+
60
+ pip uninstall ayon-python-api
61
+
62
+
63
+ ## TODOs
64
+ - Find more suitable name of `ServerAPI` objects (right now is used `con` or `connection`)
65
+ - Add all available CRUD operation on entities using REST
66
+ - Add folder and task changes to operations
67
+ - Enhance entity hub
68
+ - Entity hub should use operations session to do changes
69
+ - Entity hub could also handle 'subset', 'version' and 'representation' entities
70
+ - Missing docstrings in EntityHub -> especially entity arguments are missing
71
+ - Pass docstrings and arguments definitions from `ServerAPI` methods to global functions
72
+ - Missing websockets connection
@@ -0,0 +1,56 @@
1
+ # AYON server API
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
+
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
+
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.
7
+
8
+ ## Install
9
+ AYON python api is available on PyPi:
10
+
11
+ pip install ayon-python-api
12
+
13
+ For development purposes you may follow [build](#build-wheel) guide to build and install custom wheels.
14
+
15
+
16
+ ## Cloning the repository
17
+ Repository does not have submodules or special cases. Clone is simple as:
18
+
19
+ git clone git@github.com:ynput/ayon-python-api.git
20
+
21
+
22
+ ## Build wheel
23
+ For wheel build is required a `wheel` module from PyPi:
24
+
25
+ pip install wheel
26
+
27
+ Open terminal and change directory to ayon-python-api repository and build wheel:
28
+
29
+ cd <REPOSITORY ROOT>/ayon-python-api
30
+ python setup.py sdist bdist_wheel
31
+
32
+
33
+ Once finished a wheel should be created in `./dist/ayon_python_api-<VERSION>-py3-none-any`.
34
+
35
+ ---
36
+
37
+ ### Wheel installation
38
+ The wheel file can be used to install using pip:
39
+
40
+ pip install <REPOSITORY ROOT>/dist/ayon_python_api-<VERSION>-py3-none-any
41
+
42
+ If pip complain that `ayon-python-api` is already installed just uninstall existing one first:
43
+
44
+ pip uninstall ayon-python-api
45
+
46
+
47
+ ## TODOs
48
+ - Find more suitable name of `ServerAPI` objects (right now is used `con` or `connection`)
49
+ - Add all available CRUD operation on entities using REST
50
+ - Add folder and task changes to operations
51
+ - Enhance entity hub
52
+ - Entity hub should use operations session to do changes
53
+ - Entity hub could also handle 'subset', 'version' and 'representation' entities
54
+ - Missing docstrings in EntityHub -> especially entity arguments are missing
55
+ - Pass docstrings and arguments definitions from `ServerAPI` methods to global functions
56
+ - Missing websockets connection
@@ -673,6 +673,7 @@ class EntityHub(object):
673
673
  if entity_id in processed_ids:
674
674
  continue
675
675
  entity = self._entities_by_id[entity_id]
676
+ processed_ids.add(entity_id)
676
677
  operations_body.append(self._get_create_body(entity))
677
678
 
678
679
  for entity_id in reversed(removed_entity_ids):
@@ -877,9 +878,7 @@ class BaseEntity(object):
877
878
  if created is None:
878
879
  created = entity_id is None
879
880
 
880
- entity_id = convert_entity_id(entity_id)
881
- if entity_id is None:
882
- entity_id = create_entity_id()
881
+ entity_id = self._prepare_entity_id(entity_id)
883
882
 
884
883
  if data is None:
885
884
  data = {}
@@ -924,6 +923,12 @@ class BaseEntity(object):
924
923
  def __setitem__(self, item, value):
925
924
  return setattr(self, item, value)
926
925
 
926
+ def _prepare_entity_id(self, entity_id):
927
+ entity_id = convert_entity_id(entity_id)
928
+ if entity_id is None:
929
+ entity_id = create_entity_id()
930
+ return entity_id
931
+
927
932
  @property
928
933
  def id(self):
929
934
  """Access to entity id under which is entity available on server.
@@ -1347,6 +1352,13 @@ class ProjectEntity(BaseEntity):
1347
1352
  self._orig_folder_types = copy.deepcopy(folder_types)
1348
1353
  self._orig_task_types = copy.deepcopy(task_types)
1349
1354
 
1355
+ def _prepare_entity_id(self, entity_id):
1356
+ if entity_id != self.project_name:
1357
+ raise ValueError(
1358
+ "Unexpected entity id value \"{}\". Expected \"{}\"".format(
1359
+ entity_id, self.project_name))
1360
+ return entity_id
1361
+
1350
1362
  def get_parent(self, *args, **kwargs):
1351
1363
  return None
1352
1364
 
@@ -1426,6 +1438,10 @@ class FolderEntity(BaseEntity):
1426
1438
 
1427
1439
  def __init__(self, folder_type, *args, label=None, path=None, **kwargs):
1428
1440
  super(FolderEntity, self).__init__(*args, **kwargs)
1441
+ # Autofill project as parent of folder if is not yet set
1442
+ # - this can be guessed only if folder was just created
1443
+ if self.created and self._parent_id is UNKNOWN_VALUE:
1444
+ self._parent_id = self.project_name
1429
1445
 
1430
1446
  self._folder_type = folder_type
1431
1447
  self._label = label
@@ -1,7 +1,6 @@
1
1
  import copy
2
2
  import collections
3
3
  import uuid
4
- import datetime
5
4
  from abc import ABCMeta, abstractproperty
6
5
 
7
6
  import six
@@ -137,13 +136,20 @@ def new_version_entity(
137
136
  if data is None:
138
137
  data = {}
139
138
 
140
- return {
139
+ output = {
141
140
  "id": _create_or_convert_to_id(entity_id),
142
141
  "version": int(version),
143
142
  "subsetId": _create_or_convert_to_id(subset_id),
144
143
  "attrib": attribs,
145
144
  "data": data
146
145
  }
146
+ if task_id:
147
+ output["taskId"] = task_id
148
+ if thumbnail_id:
149
+ output["thumbnailId"] = thumbnail_id
150
+ if author:
151
+ output["author"] = author
152
+ return output
147
153
 
148
154
 
149
155
  def new_hero_version_entity(
@@ -180,13 +186,20 @@ def new_hero_version_entity(
180
186
  if data is None:
181
187
  data = {}
182
188
 
183
- return {
189
+ output = {
184
190
  "id": _create_or_convert_to_id(entity_id),
185
191
  "version": -abs(int(version)),
186
192
  "subsetId": subset_id,
187
193
  "attrib": attribs,
188
194
  "data": data
189
195
  }
196
+ if task_id:
197
+ output["taskId"] = task_id
198
+ if thumbnail_id:
199
+ output["thumbnailId"] = thumbnail_id
200
+ if author:
201
+ output["author"] = author
202
+ return output
190
203
 
191
204
 
192
205
  def new_representation_entity(
@@ -198,7 +211,6 @@ def new_representation_entity(
198
211
  name (str): Representation name considered as unique identifier
199
212
  of representation under version.
200
213
  version_id (str): Id of parent version.
201
- context (Dict[str, Any]): Representation context used to fill template.
202
214
  attribs (Dict[str, Any]): Explicitly set attributes of representation.
203
215
  data (Dict[str, Any]): Representation entity data.
204
216
  entity_id (str): Predefined id of entity. New id is created
@@ -236,6 +248,8 @@ def new_workfile_info_doc(
236
248
  task_name (str): Task under which was workfile created.
237
249
  files (List[str]): List of rootless filepaths related to workfile.
238
250
  data (Dict[str, Any]): Additional metadata.
251
+ entity_id (str): Predefined id of entity. New id is created
252
+ if not passed.
239
253
 
240
254
  Returns:
241
255
  Dict[str, Any]: Skeleton of workfile info entity.
@@ -254,153 +268,6 @@ def new_workfile_info_doc(
254
268
  }
255
269
 
256
270
 
257
- def _prepare_update_data(old_doc, new_doc, replace):
258
- changes = {}
259
- for key, value in new_doc.items():
260
- if key not in old_doc or value != old_doc[key]:
261
- changes[key] = value
262
-
263
- if replace:
264
- for key in old_doc.keys():
265
- if key not in new_doc:
266
- changes[key] = REMOVED_VALUE
267
- return changes
268
-
269
-
270
- def prepare_folder_update_data(old_doc, new_doc, replace=True):
271
- """Compare two folder entities and prepare update data.
272
-
273
- Based on compared values will create update data for
274
- 'UpdateOperation'.
275
-
276
- Empty output means that entities data are identical.
277
-
278
- Returns:
279
- Dict[str, Any]: Changes between old and new entity.
280
- """
281
-
282
- # changes = {}
283
- # for key, value in new_doc.items():
284
- # if key in ("data", ):
285
- # continue
286
- #
287
- # if key not in old_doc or value != old_doc[key]:
288
- # changes[key] = value
289
- #
290
- # return _prepare_update_data(old_doc, new_doc, replace)
291
-
292
- raise NotImplementedError(
293
- "'prepare_folder_update_data' not yet implemented"
294
- )
295
-
296
-
297
- def prepare_subset_update_data(old_doc, new_doc, replace=True):
298
- """Compare two subset entities and prepare update data.
299
-
300
- Based on compared values will create update data for
301
- 'UpdateOperation'.
302
-
303
- Empty output means that entities are identical.
304
-
305
- Returns:
306
- Dict[str, Any]: Changes between old and new entity.
307
- """
308
-
309
- # return _prepare_update_data(old_doc, new_doc, replace)
310
-
311
- raise NotImplementedError(
312
- "'prepare_folder_update_data' not yet implemented"
313
- )
314
-
315
-
316
- def prepare_version_update_data(old_doc, new_doc, replace=True):
317
- """Compare two version entities and prepare update data.
318
-
319
- Based on compared values will create update data for
320
- 'UpdateOperation'.
321
-
322
- Empty output means that entities are identical.
323
-
324
- Returns:
325
- Dict[str, Any]: Changes between old and new entity.
326
- """
327
-
328
- # return _prepare_update_data(old_doc, new_doc, replace)
329
-
330
- raise NotImplementedError(
331
- "'prepare_folder_update_data' not yet implemented"
332
- )
333
-
334
-
335
- def prepare_hero_version_update_data(old_doc, new_doc, replace=True):
336
- """Compare two hero version entities and prepare update data.
337
-
338
- Based on compared values will create update data for 'UpdateOperation'.
339
-
340
- Empty output means that entities are identical.
341
-
342
- Returns:
343
- Dict[str, Any]: Changes between old and new entity.
344
- """
345
-
346
- # return _prepare_update_data(old_doc, new_doc, replace)
347
-
348
- raise NotImplementedError(
349
- "'prepare_folder_update_data' not yet implemented"
350
- )
351
-
352
-
353
- def prepare_representation_update_data(old_doc, new_doc, replace=True):
354
- """Compare two representation entities and prepare update data.
355
-
356
- Based on compared values will create update data for
357
- 'UpdateOperation'.
358
-
359
- Empty output means that entities are identical.
360
-
361
- Returns:
362
- Dict[str, Any]: Changes between old and new entity.
363
- """
364
-
365
- # return _prepare_update_data(old_doc, new_doc, replace)
366
-
367
- raise NotImplementedError(
368
- "'prepare_folder_update_data' not yet implemented"
369
- )
370
-
371
-
372
- def prepare_workfile_info_update_data(old_doc, new_doc, replace=True):
373
- """Compare two workfile info entities and prepare update data.
374
-
375
- Based on compared values will create update data for
376
- 'UpdateOperation'.
377
-
378
- Empty output means that entities are identical.
379
-
380
- Returns:
381
- Dict[str, Any]: Changes between old and new entity.
382
- """
383
-
384
- # return _prepare_update_data(old_doc, new_doc, replace)
385
-
386
- raise NotImplementedError(
387
- "'prepare_folder_update_data' not yet implemented"
388
- )
389
-
390
-
391
- def entity_data_json_default(value):
392
- if isinstance(value, datetime.datetime):
393
- return int(value.timestamp())
394
-
395
- raise TypeError(
396
- "Object of type {} is not JSON serializable".format(str(type(value)))
397
- )
398
-
399
-
400
- def failed_json_default(value):
401
- return "< Failed value {} > {}".format(type(value), str(value))
402
-
403
-
404
271
  @six.add_metaclass(ABCMeta)
405
272
  class AbstractOperation(object):
406
273
  """Base operation class.