Skip to content

Commit 993fd74

Browse files
committed
ENH: initial implementation of 'tag-controller' API
1 parent 1d0c21e commit 993fd74

File tree

4 files changed

+313
-0
lines changed

4 files changed

+313
-0
lines changed

src/save_and_restore_api/_api_async.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,39 @@ async def config_update(self, *, configurationNode, configurationData=None, auth
108108
)
109109
return await self.send_request(method, url, params=params, auth=auth)
110110

111+
# =============================================================================================
112+
# TAG-CONTROLLER API METHODS
113+
# =============================================================================================
114+
115+
async def tags_get(self):
116+
"""
117+
Returns all existing tags.
118+
119+
API: GET /tags
120+
"""
121+
method, url = self._prepare_tags_get()
122+
return await self.send_request(method, url)
123+
124+
async def tags_add(self, *, uniqueNodeIds, tag, auth=None):
125+
"""
126+
Adds ``tag`` to nodes specified by a list of UIDs ``uniqueNodeIds``. The ``tag``
127+
dictionary must contain the ``name`` key and optionally ``comment`` key.
128+
129+
API: POST /tags
130+
"""
131+
method, url, params = self._prepare_tags_add(uniqueNodeIds=uniqueNodeIds, tag=tag)
132+
return await self.send_request(method, url, params=params, auth=auth)
133+
134+
async def tags_delete(self, *, uniqueNodeIds, tag, auth=None):
135+
"""
136+
Deletes ``tag`` to nodes specified by a list of UIDs ``uniqueNodeIds``. The ``tag``
137+
dictionary must contain the ``name`` key and optionally ``comment`` key.
138+
139+
API: DELETE /tags
140+
"""
141+
method, url, params = self._prepare_tags_delete(uniqueNodeIds=uniqueNodeIds, tag=tag)
142+
return await self.send_request(method, url, params=params, auth=auth)
143+
111144

112145
SaveRestoreAPI.node_get.__doc__ = _SaveRestoreAPI_Threads.node_get.__doc__
113146
SaveRestoreAPI.nodes_get.__doc__ = _SaveRestoreAPI_Threads.nodes_get.__doc__
@@ -119,3 +152,6 @@ async def config_update(self, *, configurationNode, configurationData=None, auth
119152
SaveRestoreAPI.config_get.__doc__ = _SaveRestoreAPI_Threads.config_get.__doc__
120153
SaveRestoreAPI.config_create.__doc__ = _SaveRestoreAPI_Threads.config_create.__doc__
121154
SaveRestoreAPI.config_update.__doc__ = _SaveRestoreAPI_Threads.config_update.__doc__
155+
SaveRestoreAPI.tags_get.__doc__ = _SaveRestoreAPI_Threads.tags_get.__doc__
156+
SaveRestoreAPI.tags_add.__doc__ = _SaveRestoreAPI_Threads.tags_add.__doc__
157+
SaveRestoreAPI.tags_delete.__doc__ = _SaveRestoreAPI_Threads.tags_delete.__doc__

src/save_and_restore_api/_api_base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,24 @@ def _prepare_config_update(self, *, configurationNode, configurationData):
223223
params = {"configurationNode": configurationNode, "configurationData": configurationData}
224224
return method, url, params
225225

226+
# =============================================================================================
227+
# TAG-CONTROLLER API METHODS
228+
# =============================================================================================
229+
230+
def _prepare_tags_get(self):
231+
method, url = "GET", "/tags"
232+
return method, url
233+
234+
def _prepare_tags_add(self, *, uniqueNodeIds, tag):
235+
method, url = "POST", "/tags"
236+
params = {"uniqueNodeIds": uniqueNodeIds, "tag": tag}
237+
return method, url, params
238+
239+
def _prepare_tags_delete(self, *, uniqueNodeIds, tag):
240+
method, url = "DELETE", "/tags"
241+
params = {"uniqueNodeIds": uniqueNodeIds, "tag": tag}
242+
return method, url, params
243+
226244
# =============================================================================================
227245

228246
# def create_config(self, parent_node_uid, name, pv_list):

src/save_and_restore_api/_api_threads.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,36 @@ def config_update(self, *, configurationNode, configurationData=None, auth=None)
164164
configurationNode=configurationNode, configurationData=configurationData
165165
)
166166
return self.send_request(method, url, params=params, auth=auth)
167+
168+
# =============================================================================================
169+
# TAG-CONTROLLER API METHODS
170+
# =============================================================================================
171+
172+
def tags_get(self):
173+
"""
174+
Returns all existing tags.
175+
176+
API: GET /tags
177+
"""
178+
method, url = self._prepare_tags_get()
179+
return self.send_request(method, url)
180+
181+
def tags_add(self, *, uniqueNodeIds, tag, auth=None):
182+
"""
183+
Adds ``tag`` to nodes specified by a list of UIDs ``uniqueNodeIds``. The ``tag``
184+
dictionary must contain the ``name`` key and optionally ``comment`` key.
185+
186+
API: POST /tags
187+
"""
188+
method, url, params = self._prepare_tags_add(uniqueNodeIds=uniqueNodeIds, tag=tag)
189+
return self.send_request(method, url, params=params, auth=auth)
190+
191+
def tags_delete(self, *, uniqueNodeIds, tag, auth=None):
192+
"""
193+
Deletes ``tag`` to nodes specified by a list of UIDs ``uniqueNodeIds``. The ``tag``
194+
dictionary must contain the ``name`` key and optionally ``comment`` key.
195+
196+
API: DELETE /tags
197+
"""
198+
method, url, params = self._prepare_tags_delete(uniqueNodeIds=uniqueNodeIds, tag=tag)
199+
return self.send_request(method, url, params=params, auth=auth)

tests/test_tag_control.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import asyncio
2+
3+
import pytest
4+
5+
from save_and_restore_api import SaveRestoreAPI as SaveRestoreAPI_Threads
6+
from save_and_restore_api.aio import SaveRestoreAPI as SaveRestoreAPI_Async
7+
8+
from .common import (
9+
_is_async,
10+
_select_auth,
11+
base_url,
12+
clear_sar, # noqa: F401
13+
user_password, # noqa: F401
14+
user_username,
15+
)
16+
17+
# =============================================================================================
18+
# TAG-CONTROLLER API METHODS
19+
# =============================================================================================
20+
21+
22+
# fmt: off
23+
@pytest.mark.parametrize("usesetauth", [True, False])
24+
@pytest.mark.parametrize("library", ["THREADS", "ASYNC"])
25+
# fmt: on
26+
def test_config_create_01(clear_sar, library, usesetauth): # noqa: F811
27+
"""
28+
Tests for the 'config_create' and 'config_get' API.
29+
"""
30+
31+
pv_list = [
32+
{
33+
"pvName": "13SIM1:{SimDetector-Cam:1}cam1:BinX"
34+
},
35+
{
36+
"pvName": "13SIM1:{SimDetector-Cam:1}cam1:BinY",
37+
"comparison": {
38+
"comparisonMode": "ABSOLUTE",
39+
"tolerance": 2.7
40+
}
41+
},
42+
{
43+
"pvName": "13SIM1:{SimDetector-Cam:2}cam2:BinX",
44+
"readbackPvName": None,
45+
"readOnly": False,
46+
},
47+
{
48+
"pvName": "13SIM1:{SimDetector-Cam:2}cam2:BinY",
49+
"readbackPvName": None,
50+
"readOnly": False,
51+
}
52+
]
53+
54+
configurationNode = {
55+
"name": "Config",
56+
}
57+
configurationData = {
58+
"pvList": pv_list,
59+
}
60+
61+
if not _is_async(library):
62+
with SaveRestoreAPI_Threads(base_url=base_url, timeout=2) as SR:
63+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
64+
65+
response = SR.node_add(SR.ROOT_NODE_UID, name="Child Folder", nodeType="FOLDER", **auth)
66+
folder_uid = response["uniqueId"]
67+
68+
69+
response = SR.config_create(
70+
folder_uid, configurationNode=configurationNode, configurationData=configurationData, **auth
71+
)
72+
assert response["configurationNode"]["name"] == "Config"
73+
assert response["configurationNode"]["nodeType"] == "CONFIGURATION"
74+
assert response["configurationNode"]["userName"] == user_username
75+
assert len(response["configurationData"]["pvList"]) == len(pv_list)
76+
77+
config_uid = response["configurationNode"]["uniqueId"]
78+
79+
response = SR.config_get(config_uid)
80+
assert response["uniqueId"] == config_uid
81+
assert len(response["pvList"]) == len(pv_list)
82+
83+
response = SR.node_get(config_uid)
84+
assert response["uniqueId"] == config_uid
85+
assert response["name"] == "Config"
86+
assert response["nodeType"] == "CONFIGURATION"
87+
assert response["userName"] == user_username
88+
89+
else:
90+
async def testing():
91+
async with SaveRestoreAPI_Async(base_url=base_url, timeout=2) as SR:
92+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
93+
94+
response = await SR.node_add(SR.ROOT_NODE_UID, name="Child Folder", nodeType="FOLDER", **auth)
95+
folder_uid = response["uniqueId"]
96+
97+
response = await SR.config_create(
98+
folder_uid, configurationNode=configurationNode, configurationData=configurationData, **auth
99+
)
100+
assert response["configurationNode"]["name"] == "Config"
101+
assert response["configurationNode"]["nodeType"] == "CONFIGURATION"
102+
assert response["configurationNode"]["userName"] == user_username
103+
assert len(response["configurationData"]["pvList"]) == len(pv_list)
104+
105+
config_uid = response["configurationNode"]["uniqueId"]
106+
107+
response = await SR.config_get(config_uid)
108+
assert response["uniqueId"] == config_uid
109+
assert len(response["pvList"]) == len(pv_list)
110+
111+
response = await SR.node_get(config_uid)
112+
assert response["uniqueId"] == config_uid
113+
assert response["name"] == "Config"
114+
assert response["nodeType"] == "CONFIGURATION"
115+
assert response["userName"] == user_username
116+
117+
asyncio.run(testing())
118+
119+
120+
# fmt: off
121+
@pytest.mark.parametrize("usesetauth", [True, False])
122+
@pytest.mark.parametrize("library", ["THREADS", "ASYNC"])
123+
# fmt: on
124+
def test_config_update_01(clear_sar, library, usesetauth): # noqa: F811
125+
"""
126+
Tests for the 'config_update' API.
127+
"""
128+
129+
pv_list1 = [{"pvName": "13SIM1:{SimDetector-Cam:1}cam1:BinY"}]
130+
pv_list2 = [{"pvName": "13SIM1:{SimDetector-Cam:1}cam1:BinX"}]
131+
132+
if not _is_async(library):
133+
with SaveRestoreAPI_Threads(base_url=base_url, timeout=2) as SR:
134+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
135+
136+
response = SR.node_add(SR.ROOT_NODE_UID, name="Child Folder", nodeType="FOLDER", **auth)
137+
folder_uid = response["uniqueId"]
138+
139+
response = SR.config_create(
140+
folder_uid, configurationNode={"name": "Config"}, configurationData={"pvList": pv_list1}, **auth
141+
)
142+
configurationNode = response["configurationNode"]
143+
configurationData = response["configurationData"]
144+
145+
assert configurationNode["name"] == "Config"
146+
assert configurationNode["nodeType"] == "CONFIGURATION"
147+
assert configurationNode["userName"] == user_username
148+
assert len(configurationData["pvList"]) == 1
149+
assert configurationData["pvList"][0]["pvName"] == pv_list1[0]["pvName"]
150+
151+
config_uid = configurationNode["uniqueId"]
152+
153+
configurationData["pvList"] = pv_list2
154+
response = SR.config_update(
155+
configurationNode=configurationNode, configurationData=configurationData, **auth
156+
)
157+
158+
configurationNode = response["configurationNode"]
159+
configurationData = response["configurationData"]
160+
161+
assert configurationNode["name"] == "Config"
162+
assert configurationNode["uniqueId"] == config_uid
163+
assert configurationData["pvList"][0]["pvName"] == pv_list2[0]["pvName"]
164+
assert configurationData["uniqueId"] == config_uid
165+
166+
response = SR.config_get(config_uid)
167+
assert response["uniqueId"] == config_uid
168+
assert len(response["pvList"]) == len(pv_list2)
169+
assert response["pvList"][0]["pvName"] == pv_list2[0]["pvName"]
170+
171+
response = SR.node_get(config_uid)
172+
assert response["uniqueId"] == config_uid
173+
assert response["name"] == "Config"
174+
assert response["nodeType"] == "CONFIGURATION"
175+
assert response["userName"] == user_username
176+
177+
else:
178+
async def testing():
179+
async with SaveRestoreAPI_Async(base_url=base_url, timeout=2) as SR:
180+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
181+
182+
response = await SR.node_add(SR.ROOT_NODE_UID, name="Child Folder", nodeType="FOLDER", **auth)
183+
folder_uid = response["uniqueId"]
184+
185+
response = await SR.config_create(
186+
folder_uid,
187+
configurationNode={"name": "Config"},
188+
configurationData={"pvList": pv_list1},
189+
**auth,
190+
)
191+
configurationNode = response["configurationNode"]
192+
configurationData = response["configurationData"]
193+
194+
assert configurationNode["name"] == "Config"
195+
assert configurationNode["nodeType"] == "CONFIGURATION"
196+
assert configurationNode["userName"] == user_username
197+
assert len(configurationData["pvList"]) == 1
198+
assert configurationData["pvList"][0]["pvName"] == pv_list1[0]["pvName"]
199+
200+
config_uid = configurationNode["uniqueId"]
201+
202+
configurationData["pvList"] = pv_list2
203+
response = await SR.config_update(
204+
configurationNode=configurationNode, configurationData=configurationData, **auth
205+
)
206+
207+
configurationNode = response["configurationNode"]
208+
configurationData = response["configurationData"]
209+
210+
assert configurationNode["name"] == "Config"
211+
assert configurationNode["uniqueId"] == config_uid
212+
assert configurationData["pvList"][0]["pvName"] == pv_list2[0]["pvName"]
213+
assert configurationData["uniqueId"] == config_uid
214+
215+
response = await SR.config_get(config_uid)
216+
assert response["uniqueId"] == config_uid
217+
assert len(response["pvList"]) == len(pv_list2)
218+
assert response["pvList"][0]["pvName"] == pv_list2[0]["pvName"]
219+
220+
response = await SR.node_get(config_uid)
221+
assert response["uniqueId"] == config_uid
222+
assert response["name"] == "Config"
223+
assert response["nodeType"] == "CONFIGURATION"
224+
assert response["userName"] == user_username
225+
226+
asyncio.run(testing())

0 commit comments

Comments
 (0)