Skip to content

Commit 86aad32

Browse files
committed
ENH: implementations of 'filter_add', 'filters_get' and 'filter_delete' API
1 parent f98362a commit 86aad32

File tree

5 files changed

+154
-0
lines changed

5 files changed

+154
-0
lines changed

src/save_and_restore_api/_api_async.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,25 @@ async def compare(self, nodeId, *, tolerance=None, compareMode=None, skipReadbac
231231
)
232232
return await self.send_request(method, url, url_params=url_params)
233233

234+
# =============================================================================================
235+
# FILTER-CONTROLLER API METHODS
236+
# =============================================================================================
237+
238+
async def filter_add(self, filter, *, auth=None):
239+
# Reusing docstrings from the threaded version
240+
method, url, params = self._prepare_filter_add(filter=filter)
241+
return await self.send_request(method, url, params=params, auth=auth)
242+
243+
async def filters_get(self):
244+
# Reusing docstrings from the threaded version
245+
method, url = self._prepare_filters_get()
246+
return await self.send_request(method, url)
247+
248+
async def filter_delete(self, name, *, auth=None):
249+
# Reusing docstrings from the threaded version
250+
method, url = self._prepare_filter_delete(name=name)
251+
return await self.send_request(method, url, auth=auth)
252+
234253
# =============================================================================================
235254
# STRUCTURE-CONTROLLER API METHODS
236255
# =============================================================================================

src/save_and_restore_api/_api_base.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# import getpass
22
import json
33
from collections.abc import Mapping
4+
from urllib.parse import quote
45

56
import httpx
67

@@ -345,6 +346,24 @@ def _prepare_compare(self, *, nodeId, tolerance, compareMode, skipReadback):
345346
url_params = None
346347
return method, url, url_params
347348

349+
# =============================================================================================
350+
# FILTER-CONTROLLER API METHODS
351+
# =============================================================================================
352+
353+
def _prepare_filter_add(self, *, filter):
354+
method, url = "PUT", "/filter"
355+
params = filter
356+
return method, url, params
357+
358+
def _prepare_filters_get(self):
359+
method, url = "GET", "/filters"
360+
return method, url
361+
362+
def _prepare_filter_delete(self, *, name):
363+
# URL may contain spaces and special characters
364+
method, url = "DELETE", quote(f"/filter/{name}")
365+
return method, url
366+
348367
# =============================================================================================
349368
# STRUCTURE-CONTROLLER API METHODS
350369
# =============================================================================================

src/save_and_restore_api/_api_threads.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,37 @@ def compare(self, nodeId, *, tolerance=None, compareMode=None, skipReadback=None
376376
)
377377
return self.send_request(method, url, url_params=url_params)
378378

379+
# =============================================================================================
380+
# FILTER-CONTROLLER API METHODS
381+
# =============================================================================================
382+
383+
def filter_add(self, filter, *, auth=None):
384+
"""
385+
Add a filter to the list stored in the database.
386+
387+
API: PUT /filter
388+
"""
389+
method, url, params = self._prepare_filter_add(filter=filter)
390+
return self.send_request(method, url, params=params, auth=auth)
391+
392+
def filters_get(self):
393+
"""
394+
Get the list of all the filters from the database.
395+
396+
API: GET /filters
397+
"""
398+
method, url = self._prepare_filters_get()
399+
return self.send_request(method, url)
400+
401+
def filter_delete(self, name, *, auth=None):
402+
"""
403+
Delete filter with the given name from the database.
404+
405+
API: DELETE /filter/{name}
406+
"""
407+
method, url = self._prepare_filter_delete(name=name)
408+
return self.send_request(method, url, auth=auth)
409+
379410
# =============================================================================================
380411
# STRUCTURE-CONTROLLER API METHODS
381412
# =============================================================================================

tests/common.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# Unit tests will create this folder and add nodes only inside this folder.
1313
# This folder will be deleted after each test to ensure clean state.
1414
root_folder_node_name = "unit-test-root-folder"
15+
filter_prefix = "UNITTESTFILTER"
1516

1617

1718
def _is_async(library):
@@ -104,6 +105,12 @@ def _clear():
104105
for uid in reversed(uids):
105106
SR.nodes_delete([uid])
106107

108+
# Delete all filters
109+
filters = SR.filters_get()
110+
for f in filters:
111+
if f.startswith("filter_prefix"):
112+
SR.filter_delete(f["name"])
113+
107114
_clear()
108115
yield
109116
_clear()

tests/test_filter_control.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
5+
import pytest
6+
7+
from save_and_restore_api import SaveRestoreAPI as SaveRestoreAPI_Threads
8+
from save_and_restore_api.aio import SaveRestoreAPI as SaveRestoreAPI_Async
9+
10+
from .common import (
11+
_is_async,
12+
_select_auth,
13+
base_url,
14+
clear_sar, # noqa: F401
15+
filter_prefix,
16+
)
17+
18+
# =============================================================================================
19+
# TESTS FOR FILTER-CONTROLLER API METHODS
20+
# =============================================================================================
21+
22+
23+
# fmt: off
24+
@pytest.mark.parametrize("usesetauth", [True, False])
25+
@pytest.mark.parametrize("library", ["THREADS", "ASYNC"])
26+
# fmt: on
27+
def test_filter_add_01(clear_sar, ioc, library, usesetauth): # noqa: F811
28+
"""
29+
Basic tests for the 'filter_add', 'filters_get' and 'filter_delete' API.
30+
"""
31+
if not _is_async(library):
32+
with SaveRestoreAPI_Threads(base_url=base_url, timeout=10) as SR:
33+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
34+
35+
response = SR.filters_get()
36+
n_filters_baseline = len(response)
37+
38+
f1_name = filter_prefix + " Test Filter #01"
39+
f2_name = filter_prefix + " Test Filter #02"
40+
response = SR.filter_add({"name": f1_name, "filter": "name=ISrc&type=snapshot"}, **auth)
41+
response = SR.filter_add({"name": f2_name, "filter": "type=snapshot&tags=TimingTables"}, **auth)
42+
43+
response = SR.filters_get()
44+
assert len(response) == n_filters_baseline + 2
45+
46+
response = SR.filter_delete(f1_name, **auth)
47+
response = SR.filter_delete(f2_name, **auth)
48+
49+
response = SR.filters_get()
50+
assert len(response) == n_filters_baseline
51+
52+
else:
53+
async def testing():
54+
async with SaveRestoreAPI_Async(base_url=base_url, timeout=2) as SR:
55+
auth = _select_auth(SR=SR, usesetauth=usesetauth)
56+
57+
response = await SR.filters_get()
58+
n_filters_baseline = len(response)
59+
60+
f1_name = filter_prefix + " Test Filter #01"
61+
f2_name = filter_prefix + " Test Filter #02"
62+
response = await SR.filter_add(
63+
{"name": f1_name, "filter": "name=ISrc&type=snapshot"}, **auth
64+
)
65+
response = await SR.filter_add(
66+
{"name": f2_name, "filter": "type=snapshot&tags=TimingTables"}, **auth
67+
)
68+
69+
response = await SR.filters_get()
70+
assert len(response) == n_filters_baseline + 2
71+
72+
response = await SR.filter_delete(f1_name, **auth)
73+
response = await SR.filter_delete(f2_name, **auth)
74+
75+
response = await SR.filters_get()
76+
assert len(response) == n_filters_baseline
77+
78+
asyncio.run(testing())

0 commit comments

Comments
 (0)