Skip to content

Commit 90aecf5

Browse files
committed
ENH: implementation of 'config_get', 'config_create' and 'config_update' API
1 parent 765ef1e commit 90aecf5

File tree

4 files changed

+220
-31
lines changed

4 files changed

+220
-31
lines changed

src/save_and_restore_api/_api_async.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,29 @@ async def node_get_parent(self, uniqueNodeId):
8585
method, url = self._prepare_node_get_parent(uniqueNodeId=uniqueNodeId)
8686
return await self.send_request(method, url)
8787

88+
# =============================================================================================
89+
# CONFIGURATION-CONTROLLER API METHODS
90+
# =============================================================================================
91+
92+
async def config_get(self, uniqueNodeId):
93+
# Reusing docstrings from the threaded version
94+
method, url = self._prepare_config_get(uniqueNodeId=uniqueNodeId)
95+
return await self.send_request(method, url)
96+
97+
async def config_create(self, parentNodeId, *, configurationNode, configurationData, auth=None):
98+
# Reusing docstrings from the threaded version
99+
method, url, params = self._prepare_config_create(
100+
parentNodeId=parentNodeId, configurationNode=configurationNode, configurationData=configurationData
101+
)
102+
return await self.send_request(method, url, params=params, auth=auth)
103+
104+
async def config_update(self, *, configurationNode, configurationData=None, auth=None):
105+
# Reusing docstrings from the threaded version
106+
method, url, params = self._prepare_config_update(
107+
configurationNode=configurationNode, configurationData=configurationData
108+
)
109+
return await self.send_request(method, url, params=params, auth=auth)
110+
88111

89112
SaveRestoreAPI.node_get.__doc__ = _SaveRestoreAPI_Threads.node_get.__doc__
90113
SaveRestoreAPI.nodes_get.__doc__ = _SaveRestoreAPI_Threads.nodes_get.__doc__
@@ -93,3 +116,6 @@ async def node_get_parent(self, uniqueNodeId):
93116
SaveRestoreAPI.nodes_delete.__doc__ = _SaveRestoreAPI_Threads.nodes_delete.__doc__
94117
SaveRestoreAPI.node_get_children.__doc__ = _SaveRestoreAPI_Threads.node_get_children.__doc__
95118
SaveRestoreAPI.node_get_parent.__doc__ = _SaveRestoreAPI_Threads.node_get_parent.__doc__
119+
SaveRestoreAPI.config_get.__doc__ = _SaveRestoreAPI_Threads.config_get.__doc__
120+
SaveRestoreAPI.config_create.__doc__ = _SaveRestoreAPI_Threads.config_create.__doc__
121+
SaveRestoreAPI.config_update.__doc__ = _SaveRestoreAPI_Threads.config_update.__doc__

src/save_and_restore_api/_api_base.py

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# import getpass
22
import json
3-
import pprint
43
from collections.abc import Mapping
54

65
import httpx
@@ -125,7 +124,14 @@ def _process_comm_exception(self, *, method, params, client_response):
125124
response_text = ""
126125
if client_response.content:
127126
try:
128-
response_text = exc.response.json()["detail"]
127+
_, response_text = exc.response.json(), ""
128+
if isinstance(_, dict):
129+
if "detail" in _:
130+
response_text = _["detail"]
131+
elif "error" in _:
132+
response_text = _["error"]
133+
else:
134+
response_text = exc.response.text
129135
except json.JSONDecodeError:
130136
response_text = exc.response.text
131137
message = f"{exc.response.status_code}: {response_text} {exc.request.url}"
@@ -197,34 +203,54 @@ def _prepare_node_get_parent(self, *, uniqueNodeId):
197203
method, url = "GET", f"/node/{uniqueNodeId}/parent"
198204
return method, url
199205

206+
# =============================================================================================
207+
# CONFIGURATION-CONTROLLER API METHODS
208+
# =============================================================================================
209+
210+
def _prepare_config_get(self, *, uniqueNodeId):
211+
method, url = "GET", f"/config/{uniqueNodeId}"
212+
return method, url
213+
214+
def _prepare_config_create(self, *, parentNodeId, configurationNode, configurationData):
215+
method, url = "PUT", f"/config?parentNodeId={parentNodeId}"
216+
configurationData = configurationData or {}
217+
params = {"configurationNode": configurationNode, "configurationData": configurationData}
218+
return method, url, params
219+
220+
def _prepare_config_update(self, *, configurationNode, configurationData):
221+
method, url = "POST", "/config"
222+
configurationData = configurationData or {}
223+
params = {"configurationNode": configurationNode, "configurationData": configurationData}
224+
return method, url, params
225+
200226
# =============================================================================================
201227

202-
def create_config(self, parent_node_uid, name, pv_list):
203-
config_dict = {
204-
"configurationNode": {
205-
"name": name,
206-
"nodeType": "CONFIGURATION",
207-
"userName": self._username,
208-
},
209-
"configurationData": {
210-
"pvList": pv_list,
211-
},
212-
}
213-
print(f"config_dict=\n{pprint.pformat(config_dict)}")
214-
return self.send_request("PUT", f"/config?parentNodeId={parent_node_uid}", json=config_dict)
215-
216-
def update_config(self, node_uid, name, pv_list):
217-
config_dict = {
218-
"configurationNode": {
219-
"name": name,
220-
"nodeType": "CONFIGURATION",
221-
"userName": self._username,
222-
"uniqueId": node_uid,
223-
},
224-
"configurationData": {
225-
"pvList": pv_list,
226-
},
227-
}
228-
print(f"config_dict=\n{pprint.pformat(config_dict)}")
229-
# return self.send_request("POST", f"/config/{node_uid}", json=config_dict)
230-
return self.send_request("POST", "/config", json=config_dict)
228+
# def create_config(self, parent_node_uid, name, pv_list):
229+
# config_dict = {
230+
# "configurationNode": {
231+
# "name": name,
232+
# "nodeType": "CONFIGURATION",
233+
# "userName": self._username,
234+
# },
235+
# "configurationData": {
236+
# "pvList": pv_list,
237+
# },
238+
# }
239+
# print(f"config_dict=\n{pprint.pformat(config_dict)}")
240+
# return self.send_request("PUT", f"/config?parentNodeId={parent_node_uid}", json=config_dict)
241+
242+
# def update_config(self, node_uid, name, pv_list):
243+
# config_dict = {
244+
# "configurationNode": {
245+
# "name": name,
246+
# "nodeType": "CONFIGURATION",
247+
# "userName": self._username,
248+
# "uniqueId": node_uid,
249+
# },
250+
# "configurationData": {
251+
# "pvList": pv_list,
252+
# },
253+
# }
254+
# print(f"config_dict=\n{pprint.pformat(config_dict)}")
255+
# # return self.send_request("POST", f"/config/{node_uid}", json=config_dict)
256+
# return self.send_request("POST", "/config", json=config_dict)

src/save_and_restore_api/_api_threads.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,38 @@ def node_get_parent(self, uniqueNodeId):
114114
"""
115115
method, url = self._prepare_node_get_parent(uniqueNodeId=uniqueNodeId)
116116
return self.send_request(method, url)
117+
118+
# =============================================================================================
119+
# CONFIGURATION-CONTROLLER API METHODS
120+
# =============================================================================================
121+
122+
def config_get(self, uniqueNodeId):
123+
"""
124+
Returns the config data for the node with specified node UID.
125+
126+
API: GET /config/{uniqueNodeId}
127+
"""
128+
method, url = self._prepare_config_get(uniqueNodeId=uniqueNodeId)
129+
return self.send_request(method, url)
130+
131+
def config_create(self, parentNodeId, *, configurationNode, configurationData, auth=None):
132+
"""
133+
Creates a new configuration node under the specified parent node.
134+
135+
API: PUT /config?parentNodeId={parentNodeId}
136+
"""
137+
method, url, params = self._prepare_config_create(
138+
parentNodeId=parentNodeId, configurationNode=configurationNode, configurationData=configurationData
139+
)
140+
return self.send_request(method, url, params=params, auth=auth)
141+
142+
def config_update(self, *, configurationNode, configurationData=None, auth=None):
143+
"""
144+
Updates an existing configuration node.
145+
146+
API: POST /config
147+
"""
148+
method, url, params = self._prepare_config_update(
149+
configurationNode=configurationNode, configurationData=configurationData
150+
)
151+
return self.send_request(method, url, params=params, auth=auth)

tests/test_package.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,108 @@ async def testing():
427427
asyncio.run(testing())
428428

429429

430+
# =============================================================================================
431+
# CONFIGURATION-CONTROLLER API METHODS
432+
# =============================================================================================
433+
434+
435+
# fmt: off
436+
@pytest.mark.parametrize("usesetauth", [True, False])
437+
@pytest.mark.parametrize("library", ["THREADS", "ASYNC"])
438+
# fmt: on
439+
def test_config_create_01(clear_sar, library, usesetauth): # noqa: F811
440+
"""
441+
Tests for the 'config_create' and 'config_get' API.
442+
"""
443+
444+
pv_list = [
445+
{
446+
"pvName": "13SIM1:{SimDetector-Cam:1}cam1:BinX"
447+
},
448+
{
449+
"pvName": "13SIM1:{SimDetector-Cam:1}cam1:BinY",
450+
"comparison": {
451+
"comparisonMode": "ABSOLUTE",
452+
"tolerance": 2.7
453+
}
454+
},
455+
{
456+
"pvName": "13SIM1:{SimDetector-Cam:2}cam2:BinX",
457+
"readbackPvName": None,
458+
"readOnly": False,
459+
},
460+
{
461+
"pvName": "13SIM1:{SimDetector-Cam:2}cam2:BinY",
462+
"readbackPvName": None,
463+
"readOnly": False,
464+
}
465+
]
466+
467+
configurationNode = {
468+
"name": "Config",
469+
}
470+
configurationData = {
471+
"pvList": pv_list,
472+
}
473+
474+
if not _is_async(library):
475+
with SaveRestoreAPI_Threads(base_url=base_url, timeout=2) as SR:
476+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
477+
478+
response = SR.node_add(SR.ROOT_NODE_UID, name="Child Folder", nodeType="FOLDER", **auth)
479+
folder_uid = response["uniqueId"]
480+
481+
482+
response = SR.config_create(
483+
folder_uid, configurationNode=configurationNode, configurationData=configurationData, **auth
484+
)
485+
assert response["configurationNode"]["name"] == "Config"
486+
assert response["configurationNode"]["nodeType"] == "CONFIGURATION"
487+
assert response["configurationNode"]["userName"] == user_username
488+
assert len(response["configurationData"]["pvList"]) == len(pv_list)
489+
490+
config_uid = response["configurationNode"]["uniqueId"]
491+
492+
response = SR.config_get(config_uid)
493+
assert response["uniqueId"] == config_uid
494+
assert len(response["pvList"]) == len(pv_list)
495+
496+
response = SR.node_get(config_uid)
497+
assert response["uniqueId"] == config_uid
498+
assert response["name"] == "Config"
499+
assert response["nodeType"] == "CONFIGURATION"
500+
assert response["userName"] == user_username
501+
502+
else:
503+
async def testing():
504+
async with SaveRestoreAPI_Async(base_url=base_url, timeout=2) as SR:
505+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
506+
507+
response = await SR.node_add(SR.ROOT_NODE_UID, name="Child Folder", nodeType="FOLDER", **auth)
508+
folder_uid = response["uniqueId"]
509+
510+
response = await SR.config_create(
511+
folder_uid, configurationNode=configurationNode, configurationData=configurationData, **auth
512+
)
513+
assert response["configurationNode"]["name"] == "Config"
514+
assert response["configurationNode"]["nodeType"] == "CONFIGURATION"
515+
assert response["configurationNode"]["userName"] == user_username
516+
assert len(response["configurationData"]["pvList"]) == len(pv_list)
517+
518+
config_uid = response["configurationNode"]["uniqueId"]
519+
520+
response = await SR.config_get(config_uid)
521+
assert response["uniqueId"] == config_uid
522+
assert len(response["pvList"]) == len(pv_list)
523+
524+
response = await SR.node_get(config_uid)
525+
assert response["uniqueId"] == config_uid
526+
assert response["name"] == "Config"
527+
assert response["nodeType"] == "CONFIGURATION"
528+
assert response["userName"] == user_username
529+
530+
asyncio.run(testing())
531+
430532

431533

432534

0 commit comments

Comments
 (0)