Skip to content

Commit 69d5f09

Browse files
authored
Merge pull request #265 from ynput/enhancement/add-actions-functionality
Actions: Added actions functionality
2 parents 08f4c73 + dc44738 commit 69d5f09

File tree

7 files changed

+676
-3
lines changed

7 files changed

+676
-3
lines changed

automated_api.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@
3030
sys.modules["unidecode"] = type(sys)("unidecode")
3131

3232
import ayon_api # noqa: E402
33-
from ayon_api.server_api import ServerAPI, _PLACEHOLDER # noqa: E402
33+
from ayon_api.server_api import ( # noqa: E402
34+
ServerAPI,
35+
_PLACEHOLDER,
36+
_ActionsAPI,
37+
)
3438
from ayon_api.utils import NOT_SET # noqa: E402
3539

3640
EXCLUDED_METHODS = {
@@ -288,7 +292,9 @@ def sig_params_to_str(sig, param_names, api_globals, indent=0):
288292

289293
def prepare_api_functions(api_globals):
290294
functions = []
291-
for attr_name, attr in ServerAPI.__dict__.items():
295+
_items = list(ServerAPI.__dict__.items())
296+
_items.extend(_ActionsAPI.__dict__.items())
297+
for attr_name, attr in _items:
292298
if (
293299
attr_name.startswith("_")
294300
or attr_name in EXCLUDED_METHODS

ayon_api/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,12 @@
243243
get_representation_links,
244244
send_batch_operations,
245245
send_activities_batch_operations,
246+
get_actions,
247+
trigger_action,
248+
get_action_config,
249+
set_action_config,
250+
take_action,
251+
abort_action,
246252
)
247253

248254

@@ -489,4 +495,10 @@
489495
"get_representation_links",
490496
"send_batch_operations",
491497
"send_activities_batch_operations",
498+
"get_actions",
499+
"trigger_action",
500+
"get_action_config",
501+
"set_action_config",
502+
"take_action",
503+
"abort_action",
492504
)

ayon_api/_actions.py

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
import typing
2+
from typing import Optional, Dict, List, Any
3+
4+
from .utils import prepare_query_string
5+
from ._base import _BaseServerAPI
6+
7+
if typing.TYPE_CHECKING:
8+
from .typing import (
9+
ActionEntityTypes,
10+
ActionManifestDict,
11+
ActionTriggerResponse,
12+
ActionTakeResponse,
13+
ActionConfigResponse,
14+
ActionModeType,
15+
)
16+
17+
18+
class _ActionsAPI(_BaseServerAPI):
19+
"""Implementation of actions API for ServerAPI."""
20+
def get_actions(
21+
self,
22+
project_name: Optional[str] = None,
23+
entity_type: Optional["ActionEntityTypes"] = None,
24+
entity_ids: Optional[List[str]] = None,
25+
entity_subtypes: Optional[List[str]] = None,
26+
form_data: Optional[Dict[str, Any]] = None,
27+
*,
28+
variant: Optional[str] = None,
29+
mode: Optional["ActionModeType"] = None,
30+
) -> List["ActionManifestDict"]:
31+
"""Get actions for a context.
32+
33+
Args:
34+
project_name (Optional[str]): Name of the project. None for global
35+
actions.
36+
entity_type (Optional[ActionEntityTypes]): Entity type where the
37+
action is triggered. None for global actions.
38+
entity_ids (Optional[List[str]]): List of entity ids where the
39+
action is triggered. None for global actions.
40+
entity_subtypes (Optional[List[str]]): List of entity subtypes
41+
folder types for folder ids, task types for tasks ids.
42+
form_data (Optional[Dict[str, Any]]): Form data of the action.
43+
variant (Optional[str]): Settings variant.
44+
mode (Optional[ActionModeType]): Action modes.
45+
46+
Returns:
47+
List[ActionManifestDict]: List of action manifests.
48+
49+
"""
50+
if variant is None:
51+
variant = self.get_default_settings_variant()
52+
query_data = {"variant": variant}
53+
if mode:
54+
query_data["mode"] = mode
55+
query = prepare_query_string(query_data)
56+
kwargs = {
57+
key: value
58+
for key, value in (
59+
("projectName", project_name),
60+
("entityType", entity_type),
61+
("entityIds", entity_ids),
62+
("entitySubtypes", entity_subtypes),
63+
("formData", form_data),
64+
)
65+
if value is not None
66+
}
67+
response = self.post(f"actions/list{query}", **kwargs)
68+
response.raise_for_status()
69+
return response.data["actions"]
70+
71+
def trigger_action(
72+
self,
73+
identifier: str,
74+
addon_name: str,
75+
addon_version: str,
76+
project_name: Optional[str] = None,
77+
entity_type: Optional["ActionEntityTypes"] = None,
78+
entity_ids: Optional[List[str]] = None,
79+
entity_subtypes: Optional[List[str]] = None,
80+
form_data: Optional[Dict[str, Any]] = None,
81+
*,
82+
variant: Optional[str] = None,
83+
) -> "ActionTriggerResponse":
84+
"""Trigger action.
85+
86+
Args:
87+
identifier (str): Identifier of the action.
88+
addon_name (str): Name of the addon.
89+
addon_version (str): Version of the addon.
90+
project_name (Optional[str]): Name of the project. None for global
91+
actions.
92+
entity_type (Optional[ActionEntityTypes]): Entity type where the
93+
action is triggered. None for global actions.
94+
entity_ids (Optional[List[str]]): List of entity ids where the
95+
action is triggered. None for global actions.
96+
entity_subtypes (Optional[List[str]]): List of entity subtypes
97+
folder types for folder ids, task types for tasks ids.
98+
form_data (Optional[Dict[str, Any]]): Form data of the action.
99+
variant (Optional[str]): Settings variant.
100+
101+
"""
102+
if variant is None:
103+
variant = self.get_default_settings_variant()
104+
query_data = {
105+
"addonName": addon_name,
106+
"addonVersion": addon_version,
107+
"identifier": identifier,
108+
"variant": variant,
109+
}
110+
query = prepare_query_string(query_data)
111+
112+
kwargs = {
113+
key: value
114+
for key, value in (
115+
("projectName", project_name),
116+
("entityType", entity_type),
117+
("entityIds", entity_ids),
118+
("entitySubtypes", entity_subtypes),
119+
("formData", form_data),
120+
)
121+
if value is not None
122+
}
123+
124+
response = self.post(f"actions/execute{query}", **kwargs)
125+
response.raise_for_status()
126+
return response.data
127+
128+
def get_action_config(
129+
self,
130+
identifier: str,
131+
addon_name: str,
132+
addon_version: str,
133+
project_name: Optional[str] = None,
134+
entity_type: Optional["ActionEntityTypes"] = None,
135+
entity_ids: Optional[List[str]] = None,
136+
entity_subtypes: Optional[List[str]] = None,
137+
form_data: Optional[Dict[str, Any]] = None,
138+
*,
139+
variant: Optional[str] = None,
140+
) -> "ActionConfigResponse":
141+
"""Get action configuration.
142+
143+
Args:
144+
identifier (str): Identifier of the action.
145+
addon_name (str): Name of the addon.
146+
addon_version (str): Version of the addon.
147+
project_name (Optional[str]): Name of the project. None for global
148+
actions.
149+
entity_type (Optional[ActionEntityTypes]): Entity type where the
150+
action is triggered. None for global actions.
151+
entity_ids (Optional[List[str]]): List of entity ids where the
152+
action is triggered. None for global actions.
153+
entity_subtypes (Optional[List[str]]): List of entity subtypes
154+
folder types for folder ids, task types for tasks ids.
155+
form_data (Optional[Dict[str, Any]]): Form data of the action.
156+
variant (Optional[str]): Settings variant.
157+
158+
Returns:
159+
ActionConfigResponse: Action configuration data.
160+
161+
"""
162+
return self._send_config_request(
163+
identifier,
164+
addon_name,
165+
addon_version,
166+
None,
167+
project_name,
168+
entity_type,
169+
entity_ids,
170+
entity_subtypes,
171+
form_data,
172+
variant,
173+
)
174+
175+
def set_action_config(
176+
self,
177+
identifier: str,
178+
addon_name: str,
179+
addon_version: str,
180+
value: Dict[str, Any],
181+
project_name: Optional[str] = None,
182+
entity_type: Optional["ActionEntityTypes"] = None,
183+
entity_ids: Optional[List[str]] = None,
184+
entity_subtypes: Optional[List[str]] = None,
185+
form_data: Optional[Dict[str, Any]] = None,
186+
*,
187+
variant: Optional[str] = None,
188+
) -> "ActionConfigResponse":
189+
"""Set action configuration.
190+
191+
Args:
192+
identifier (str): Identifier of the action.
193+
addon_name (str): Name of the addon.
194+
addon_version (str): Version of the addon.
195+
value (Optional[Dict[str, Any]]): Value of the action
196+
configuration.
197+
project_name (Optional[str]): Name of the project. None for global
198+
actions.
199+
entity_type (Optional[ActionEntityTypes]): Entity type where the
200+
action is triggered. None for global actions.
201+
entity_ids (Optional[List[str]]): List of entity ids where the
202+
action is triggered. None for global actions.
203+
entity_subtypes (Optional[List[str]]): List of entity subtypes
204+
folder types for folder ids, task types for tasks ids.
205+
form_data (Optional[Dict[str, Any]]): Form data of the action.
206+
variant (Optional[str]): Settings variant.
207+
208+
Returns:
209+
ActionConfigResponse: New action configuration data.
210+
211+
"""
212+
return self._send_config_request(
213+
identifier,
214+
addon_name,
215+
addon_version,
216+
value,
217+
project_name,
218+
entity_type,
219+
entity_ids,
220+
entity_subtypes,
221+
form_data,
222+
variant,
223+
)
224+
225+
def take_action(self, action_token: str) -> "ActionTakeResponse":
226+
"""Take action metadata using an action token.
227+
228+
Args:
229+
action_token (str): AYON launcher action token.
230+
231+
Returns:
232+
ActionTakeResponse: Action metadata describing how to launch
233+
action.
234+
235+
"""
236+
response = self.get(f"actions/abort/{action_token}")
237+
response.raise_for_status()
238+
return response.data
239+
240+
def abort_action(
241+
self,
242+
action_token: str,
243+
message: Optional[str] = None,
244+
) -> None:
245+
"""Abort action using an action token.
246+
247+
Args:
248+
action_token (str): AYON launcher action token.
249+
message (Optional[str]): Message to display in the UI.
250+
251+
"""
252+
if message is None:
253+
message = "Action aborted"
254+
response = self.post(
255+
f"actions/abort/{action_token}",
256+
message=message,
257+
)
258+
response.raise_for_status()
259+
260+
def _send_config_request(
261+
self,
262+
identifier: str,
263+
addon_name: str,
264+
addon_version: str,
265+
value: Optional[Dict[str, Any]],
266+
project_name: Optional[str],
267+
entity_type: Optional["ActionEntityTypes"],
268+
entity_ids: Optional[List[str]],
269+
entity_subtypes: Optional[List[str]],
270+
form_data: Optional[Dict[str, Any]],
271+
variant: Optional[str],
272+
) -> "ActionConfigResponse":
273+
"""Set and get action configuration."""
274+
if variant is None:
275+
variant = self.get_default_settings_variant()
276+
query_data = {
277+
"addonName": addon_name,
278+
"addonVersion": addon_version,
279+
"identifier": identifier,
280+
"variant": variant,
281+
}
282+
query = prepare_query_string(query_data)
283+
284+
kwargs = {
285+
query_key: query_value
286+
for query_key, query_value in (
287+
("projectName", project_name),
288+
("entityType", entity_type),
289+
("entityIds", entity_ids),
290+
("entitySubtypes", entity_subtypes),
291+
("formData", form_data),
292+
)
293+
if query_value is not None
294+
}
295+
if value is not None:
296+
kwargs["value"] = value
297+
298+
response = self.post(f"actions/config{query}", **kwargs)
299+
response.raise_for_status()
300+
return response.data

0 commit comments

Comments
 (0)