Skip to content

Commit 2cc4c7c

Browse files
committed
feat(sdk): add ability to disable auto save
1 parent aec99c2 commit 2cc4c7c

File tree

5 files changed

+68
-27
lines changed

5 files changed

+68
-27
lines changed

sdk/python/scilog/authmixin.py

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ def typename(obj):
1414
class AuthMixin(ABC):
1515
def __init__(self, address, options=None):
1616
self.address = address.rstrip("/")
17+
if not options:
18+
options = {}
19+
self._auto_save_token = options.get("auto_save_token", True)
1720
tn = typename(self).lower()
1821
try:
19-
self.config = Config(f".{tn}-tokens")
22+
self.config = Config(f".{tn}-tokens", auto_save_token=self._auto_save_token)
2023
except JSONDecodeError:
2124
self.config = {}
22-
if not options:
23-
options = {}
25+
2426
self._token = options.get("token")
2527
self._username = options.get("username")
2628
self._password = options.get("password")
@@ -39,19 +41,33 @@ def authenticate(self, username, password):
3941
def token(self):
4042
return self._retrieve_token()
4143

44+
def reset_token(self):
45+
self._token = None
46+
4247
def _retrieve_token(self):
4348
username = self._username or getpass.getuser()
44-
token = self._token
45-
if token is None:
46-
try:
47-
token = self.config[username]
48-
except KeyError:
49-
tn = typename(self)
50-
password = self._password or getpass.getpass(
51-
prompt=f"{tn} password for {username}: "
52-
)
53-
token = self.authenticate(username, password)
54-
self.config[username] = self._token = token
49+
50+
if self._token:
51+
# If a token is already set (either from options or from a previous authentication), use it.
52+
return self._token
53+
54+
if not self._auto_save_token:
55+
# If auto-saving is disabled, authenticate without checking the config.
56+
self._token = self._authenticate()
57+
return self._token
58+
59+
try:
60+
self._token = self.config[username]
61+
except KeyError:
62+
self._token = self._authenticate()
63+
self.config[username] = self._token
64+
return self._token
65+
66+
def _authenticate(self):
67+
tn = typename(self)
68+
username = self._username or getpass.getuser()
69+
password = self._password or getpass.getpass(prompt=f"{tn} password for {username}: ")
70+
token = self.authenticate(username, password)
5571
return token
5672

5773

sdk/python/scilog/config.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33

44

55
class Config(dict):
6-
def __init__(self, fname, folder=None):
6+
def __init__(self, fname, folder=None, auto_save_token=True):
77
if folder is not None:
88
folder = Path(folder)
99
else:
1010
folder = Path.home()
1111
self.fname = folder / fname
12+
self.auto_save_token = auto_save_token
1213
content = self._load()
1314
super().__init__(content)
1415

@@ -30,7 +31,8 @@ def _save(self):
3031
json_save(self, self.fname)
3132

3233
def delete(self):
33-
self.fname.unlink()
34+
if self.fname.exists():
35+
self.fname.unlink()
3436

3537

3638
def json_save(what, filename, *args, indent=4, sort_keys=True, **kwargs):

sdk/python/scilog/httpclient.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,15 @@ def authenticate(self, username, password):
6060
def get_request(self, url, params=None, headers=None, timeout=10):
6161
logger.debug(f"Getting data request: {url} , {params}")
6262
response = requests.get(
63-
url,
64-
params=params,
65-
headers=headers,
66-
timeout=timeout,
67-
verify=self._verify_certificate,
63+
url, params=params, headers=headers, timeout=timeout, verify=self._verify_certificate
6864
)
6965
if response.ok:
7066
logger.debug(f"Getting data response: {response.json()}")
7167
return response.json()
72-
else:
73-
if response.reason == "Unauthorized":
74-
self.config.delete()
75-
raise response.raise_for_status()
68+
69+
if response.reason == "Unauthorized":
70+
self.config.delete()
71+
raise response.raise_for_status()
7672

7773
@authenticated
7874
@formatted_http_error

sdk/python/scilog/scilog.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,19 @@ def patch_snippet(self, snippet: T, **kwargs) -> T:
375375

376376

377377
class SciLog:
378-
def __init__(self, *args, **kwargs):
379-
self.http_client = SciLogRestAPI(*args, **kwargs)
378+
def __init__(self, address: str, options: dict | None = None, **kwargs):
379+
"""
380+
Initialize the SciLog client.
381+
382+
Args:
383+
address (str): The base URL of the SciLog server, e.g. "https://scilog.psi.ch/api/v1"
384+
options (dict | None): Optional dictionary containing authentication options such as
385+
"token", "username", "password", "login_path" and "auto_save_token". If not
386+
provided, the client will attempt to retrieve these from the environment or
387+
prompt the user.
388+
**kwargs: Additional keyword arguments for authentication, if needed.
389+
"""
390+
self.http_client = SciLogRestAPI(address=address, options=options, **kwargs)
380391
self.logbook = None
381392
self.core = SciLogCore(self)
382393

sdk/python/tests/test_scilog.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,19 @@ def test_get_snippets_with_kwargs_calls_http(scilog):
271271
assert headers == HEADER_JSON
272272
filt = json.loads(params["filter"])
273273
assert filt == {"where": {"and": [{"textcontent": "text", "parentId": "logbook_id_test"}]}}
274+
275+
276+
def test_scilog_without_auto_save_does_not_use_config(scilog):
277+
log = SciLog("fake_url", options={"auto_save_token": False})
278+
assert log.http_client._auto_save_token is False
279+
with mock.patch.object(
280+
log.core.http_client, "_authenticate", return_value="dummy_token"
281+
) as mock_authenticate:
282+
with mock.patch.object(log.core.http_client, "config") as mock_config:
283+
token = log.http_client.token
284+
mock_authenticate.assert_called_once()
285+
286+
# Ensure that the config is neither read from nor written to when auto_save_token is False
287+
mock_config.__getitem__.assert_not_called()
288+
mock_config.__setitem__.assert_not_called()
289+
assert token == "dummy_token"

0 commit comments

Comments
 (0)