Skip to content

Commit

Permalink
Make cache path configurable and include URL in cache key
Browse files Browse the repository at this point in the history
Including the base URL in the hashed part of the filename just makes
sense, even though I'm not aware of any differences in the two public
instances of Space-Track (production and testing).

Making the cache path configurable helps any downstream testing which
might use a mock Space-Track server.
  • Loading branch information
RazerM committed Feb 24, 2025
1 parent b91aa5a commit ccdd72b
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 26 deletions.
2 changes: 2 additions & 0 deletions src/spacetrack/aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(
rush_key_prefix="",
httpx_client=None,
additional_rate_limit=None,
cache_path=None,
):
if httpx_client is None:
httpx_client = httpx.AsyncClient()
Expand All @@ -61,6 +62,7 @@ def __init__(
rush_key_prefix=rush_key_prefix,
httpx_client=httpx_client,
additional_rate_limit=additional_rate_limit,
cache_path=cache_path,
)

def _setup_finalizer(self):
Expand Down
21 changes: 14 additions & 7 deletions src/spacetrack/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import hashlib
import json
import re
import sys
Expand All @@ -18,7 +19,7 @@
import outcome
from filelock import FileLock
from logbook import Logger
from platformdirs import PlatformDirs
from platformdirs import user_cache_path
from represent import ReprHelper, ReprHelperMixin
from rush.limiters.periodic import PeriodicLimiter
from rush.quota import Quota
Expand Down Expand Up @@ -179,6 +180,7 @@ class SpaceTrackClient:
for a proxy).
additional_rate_limit: Optionally, a :class:`rush.quota.Quota` if you
want to restrict the rate limit further than the defaults.
cache_path: Optionally, which directory to use for the cache.
For more information, refer to the `Space-Track documentation`_.
Expand Down Expand Up @@ -318,6 +320,7 @@ def __init__(
rush_key_prefix="",
httpx_client=None,
additional_rate_limit=None,
cache_path=None,
):
if httpx_client is None:
httpx_client = httpx.Client()
Expand Down Expand Up @@ -363,7 +366,10 @@ def __init__(
else:
raise TypeError("additional_rate_limit must be a rush.quota.Quota")

self._dirs = PlatformDirs("spacetrack")
if cache_path is None:
self._cache_path = user_cache_path("spacetrack")
else:
self._cache_path = Path(cache_path)

self._setup_finalizer()

Expand Down Expand Up @@ -850,16 +856,17 @@ def _get_predicates_generator(self, class_, controller, *, force=False):
key = f"{controller}.{class_}"

if key not in self._predicates or (force and self._predicates[key] is None):
cache_path = self._dirs.user_cache_path

cache_file = cache_path / f"predicates-{key}.json"

hasher = hashlib.sha256()
hasher.update(self.base_url.encode())
hasher.update(key.encode())
hashkey = hasher.hexdigest()[:16]
cache_file = self._cache_path / f"predicates-{hashkey}.json"
predicates_data = self._read_cache_file(
cache_file, PREDICATE_CACHE_EXPIRY_TIME
)

if predicates_data is None:
cache_path.mkdir(parents=True, exist_ok=True)
self._cache_path.mkdir(parents=True, exist_ok=True)

lock_file = cache_file.with_name(cache_file.name + ".lock")
lock = self._file_lock_cls(lock_file)
Expand Down
11 changes: 3 additions & 8 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,10 @@ def respx_mock(respx_router):

@pytest.fixture(autouse=True)
def temporary_cache_dir(monkeypatch, tmp_path):
class MockPlatformDirs:
def __init__(self, appname):
pass
def user_cache_path(appname):
return tmp_path

@property
def user_cache_path(self):
return tmp_path

with patch("spacetrack.base.PlatformDirs", MockPlatformDirs):
with patch("spacetrack.base.user_cache_path", user_cache_path):
yield


Expand Down
18 changes: 12 additions & 6 deletions tests/test_aio.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,10 @@ async def test_modeldef_cache(respx_mock, mock_auth, cache_file_mangler):
assert await client.gp(norad_cat_id=25541) == "dummy"
assert modeldef_route.call_count == 1

cache_path = client._dirs.user_cache_path
cache_files = list(cache_path.glob("*.json"))
assert [str(p.relative_to(cache_path)) for p in cache_files] == [
"predicates-basicspacedata.gp.json"
]
cache_files = list(client._cache_path.glob("*.json"))
assert len(cache_files) == 1
assert cache_files[0].name.startswith("predicates-")
assert cache_files[0].name.endswith(".json")

for file in cache_files:
cache_file_mangler(file)
Expand Down Expand Up @@ -234,6 +233,13 @@ async def test_modeldef_not_used_trio(respx_mock, mock_auth):
assert await client.gp(norad_cat_id=25541) == "dummy"
assert modeldef_route.call_count == 1

cache_path = client._dirs.user_cache_path
cache_path = client._cache_path
cache_files = list(cache_path.glob("*.json"))
assert cache_files == []


async def test_custom_cache_path(async_runner, respx_mock, tmp_path):
async with AsyncSpaceTrackClient(
"identity", "password", cache_path=tmp_path
) as client:
assert client._cache_path == tmp_path
14 changes: 9 additions & 5 deletions tests/test_spacetrack.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,11 +591,10 @@ def test_modeldef_cache(respx_mock, mock_auth, cache_file_mangler):
assert client.gp(norad_cat_id=25541) == "dummy"
assert modeldef_route.call_count == 1

cache_path = client._dirs.user_cache_path
cache_files = list(cache_path.glob("*.json"))
assert [str(p.relative_to(cache_path)) for p in cache_files] == [
"predicates-basicspacedata.gp.json"
]
cache_files = list(client._cache_path.glob("*.json"))
assert len(cache_files) == 1
assert cache_files[0].name.startswith("predicates-")
assert cache_files[0].name.endswith(".json")

for file in cache_files:
cache_file_mangler(file)
Expand All @@ -614,3 +613,8 @@ def test_modeldef_cache(respx_mock, mock_auth, cache_file_mangler):
def test_implicit_cleanup_warning():
with pytest.warns(ResourceWarning, match="without being closed explicitly"):
SpaceTrackClient("identity", "password")


def test_custom_cache_path(respx_mock, tmp_path):
with SpaceTrackClient("identity", "password", cache_path=tmp_path) as client:
assert client._cache_path == tmp_path

0 comments on commit ccdd72b

Please sign in to comment.