diff --git a/conservancy_beancount/config.py b/conservancy_beancount/config.py index fd9f27869595f67d036aa698af342c7e9ab74d41..95d763e5461cc66effb3febee5e5a803d8672b0d 100644 --- a/conservancy_beancount/config.py +++ b/conservancy_beancount/config.py @@ -65,6 +65,18 @@ class RTCredentials(NamedTuple): else: return cls(**values) + def idstr(self) -> str: + """Return a string unique to these credentials + + This returns a string that incorporates the server URL and user. + The string will be unique across different credentials. + It's suitable for use as a cache key or filename. + """ + return '{}@{}'.format( + self.user or '', + urlparse.quote(self.server or '', ''), + ) + class Config: _ENVIRON_DEFAULT_PATHS = { @@ -209,11 +221,7 @@ class Config: if cache_dir_path is None: cache_db = None else: - cache_name = '{}@{}.sqlite3'.format( - credentials.user, - urlparse.quote(str(credentials.server), ''), - ) - cache_path = cache_dir_path / cache_name + cache_path = cache_dir_path / f'{credentials.idstr()}.sqlite3' try: cache_path.touch(0o600) except OSError: diff --git a/tests/test_config.py b/tests/test_config.py index efa2ad872be028db7fab83cb8b4ad4ab66f30c66..d124ede8ac5457a7ae5b097d3c45200fc016dece 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -7,6 +7,7 @@ import contextlib import decimal +import itertools import operator import os import re @@ -140,6 +141,17 @@ def test_rt_credentials_from_all_sources_mixed(tmp_path): rt_credentials = config.rt_credentials() assert rt_credentials == (server, 'mixedup', 'mixed up', 'rt') +def test_rt_credentials_idstr(): + actual = { + config_mod.RTCredentials(server, user).idstr() + for server, user in itertools.product( + [None, 'https://example.org/rt'], + [None, 'example'], + )} + assert len(actual) == 4 + for idstr in actual: + assert '/' not in idstr + def check_rt_client_url(credentials, client): pattern = '^{}/?$'.format(re.escape(credentials[0].rstrip('/') + '/REST/1.0')) assert re.match(pattern, client.url)