summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Cook <jordan.cook@pioneer.com>2021-08-20 23:53:27 -0500
committerJordan Cook <jordan.cook@pioneer.com>2021-08-21 14:13:28 -0500
commitca2ed80089f9f3ec73aa4953d1ae95153229669f (patch)
tree0399d474f71f1d9b67aeb4e753c3cfa10c28adbb
parent901a2b997ecc15500c1874123a399a1464342e53 (diff)
downloadrequests-cache-ca2ed80089f9f3ec73aa4953d1ae95153229669f.tar.gz
Add appdirs as a dependency, and add 'use_cache_dir' option to SQLite and Filesystem backends
-rw-r--r--poetry.lock14
-rw-r--r--pyproject.toml1
-rw-r--r--requests_cache/backends/filesystem.py28
-rw-r--r--requests_cache/backends/sqlite.py54
-rw-r--r--tests/integration/test_filesystem.py7
-rw-r--r--tests/integration/test_sqlite.py8
6 files changed, 78 insertions, 34 deletions
diff --git a/poetry.lock b/poetry.lock
index 3dfba55..29ca8c5 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -7,6 +7,14 @@ optional = false
python-versions = "*"
[[package]]
+name = "appdirs"
+version = "1.4.4"
+description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "main"
+optional = false
+python-versions = "*"
+
+[[package]]
name = "argcomplete"
version = "1.12.3"
description = "Bash tab completion for argparse"
@@ -1181,13 +1189,17 @@ yaml = []
[metadata]
lock-version = "1.1"
python-versions = "^3.7"
-content-hash = "d73d313f19bec94728639a91b739ae34bd04d1f975716df3ae938db343328562"
+content-hash = "01c4c5d4ac701b6499db508b2334b5d51fbdc773e56193ced940e73c989edc17"
[metadata.files]
alabaster = [
{file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
{file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
]
+appdirs = [
+ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
+ {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
+]
argcomplete = [
{file = "argcomplete-1.12.3-py2.py3-none-any.whl", hash = "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81"},
{file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"},
diff --git a/pyproject.toml b/pyproject.toml
index a4291c3..c7b76ee 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -26,6 +26,7 @@ include = [
[tool.poetry.dependencies]
python = "^3.7"
+appdirs = "^1.4.4"
attrs = "^21.2"
cattrs = "^1.8"
itsdangerous = "^2.0"
diff --git a/requests_cache/backends/filesystem.py b/requests_cache/backends/filesystem.py
index 63d83ba..a70a6f7 100644
--- a/requests_cache/backends/filesystem.py
+++ b/requests_cache/backends/filesystem.py
@@ -38,16 +38,15 @@ API Reference
from contextlib import contextmanager
from glob import glob
from os import listdir, makedirs, unlink
-from os.path import abspath, basename, dirname, expanduser, isabs, join, splitext
+from os.path import basename, dirname, join, splitext
from pathlib import Path
from pickle import PickleError
from shutil import rmtree
-from tempfile import gettempdir
from typing import List, Union
from ..serializers import SERIALIZERS
from . import BaseCache, BaseStorage
-from .sqlite import SQLiteDict
+from .sqlite import SQLiteDict, get_cache_path
class FileCache(BaseCache):
@@ -55,6 +54,7 @@ class FileCache(BaseCache):
Args:
cache_name: Base directory for cache files
+ use_cache_dir: Store datebase in a user cache directory (e.g., `~/.cache/`)
use_temp: Store cache files in a temp directory (e.g., ``/tmp/http_cache/``).
Note: if ``cache_name`` is an absolute path, this option will be ignored.
extension: Extension for cache files. If not specified, the serializer default extension
@@ -75,9 +75,16 @@ class FileCache(BaseCache):
class FileDict(BaseStorage):
"""A dictionary-like interface to files on the local filesystem"""
- def __init__(self, cache_name, use_temp: bool = False, extension: str = None, **kwargs):
+ def __init__(
+ self,
+ cache_name,
+ use_temp: bool = False,
+ use_cache_dir: bool = False,
+ extension: str = None,
+ **kwargs,
+ ):
super().__init__(**kwargs)
- self.cache_dir = _get_cache_dir(cache_name, use_temp)
+ self.cache_dir = get_cache_path(cache_name, use_cache_dir=use_cache_dir, use_temp=use_temp)
self.extension = extension if extension is not None else _get_default_ext(self.serializer)
self.is_binary = False
makedirs(self.cache_dir, exist_ok=True)
@@ -135,17 +142,6 @@ class FileDict(BaseStorage):
return glob(self._path('*'))
-def _get_cache_dir(cache_dir: Union[Path, str], use_temp: bool) -> str:
- # Save to a temp directory, if specified
- if use_temp and not isabs(cache_dir):
- cache_dir = join(gettempdir(), cache_dir, 'responses')
-
- # Expand relative and user paths (~/*), and make sure parent dirs exist
- cache_dir = abspath(expanduser(str(cache_dir)))
- makedirs(cache_dir, exist_ok=True)
- return cache_dir
-
-
def _get_default_ext(serializer) -> str:
for k, v in SERIALIZERS.items():
if serializer is v:
diff --git a/requests_cache/backends/sqlite.py b/requests_cache/backends/sqlite.py
index a66e228..ed671f5 100644
--- a/requests_cache/backends/sqlite.py
+++ b/requests_cache/backends/sqlite.py
@@ -54,7 +54,7 @@ Special System Paths
If you don't know exactly where you want to put your cache file, your **system's default temp
directory** or **cache directory** is a good choice.
-Use a temp directory with the ``use_temp`` option:
+Use your system's default temp directory with the ``use_temp`` option:
>>> session = CachedSession('http_cache', use_temp=True)
>>> print(session.cache.db_path)
@@ -64,12 +64,14 @@ Use a temp directory with the ``use_temp`` option:
If the cache name is an absolute path, the ``use_temp`` option will be ignored. If it's a
relative path, it will be relative to the temp directory.
+Use your system's default cache directory with the ``use_cache_dir`` option:
+
If you want an easy cross-platform way to get the system cache directory, use the
`appdirs <https://github.com/ActiveState/appdirs>`_ library:
- >>> from appdirs import user_cache_dir
- >>> db_path = join(user_cache_dir('requests_cache'), 'http_cache')
- >>> session = CachedSession(db_path, use_temp=True)
+ >>> session = CachedSession('http_cache', use_cache_dir=True)
+ >>> print(session.cache.db_path)
+ '/home/user/.cache/http_cache.sqlite'
In-Memory Caching
~~~~~~~~~~~~~~~~~
@@ -132,6 +134,8 @@ from pathlib import Path
from tempfile import gettempdir
from typing import Collection, Iterable, Iterator, List, Tuple, Type, Union
+from appdirs import user_cache_dir
+
from . import BaseCache, BaseStorage, get_valid_kwargs
MEMORY_URI = 'file::memory:?cache=shared'
@@ -144,6 +148,7 @@ class SQLiteCache(BaseCache):
Args:
db_path: Database file path (expands user paths and creates parent dirs)
+ use_cache_dir: Store datebase in a user cache directory (e.g., `~/.cache/http_cache.sqlite`)
use_temp: Store database in a temp directory (e.g., ``/tmp/http_cache.sqlite``)
use_memory: Store database in memory instead of in a file
fast_save: Significantly increases cache write performance, but with the possibility of data
@@ -191,13 +196,16 @@ class SQLiteDict(BaseStorage):
db_path,
table_name='http_cache',
fast_save=False,
- use_temp: bool = False,
+ use_cache_dir: bool = False,
use_memory: bool = False,
+ use_temp: bool = False,
**kwargs,
):
super().__init__(**kwargs)
self.connection_kwargs = get_valid_kwargs(sqlite_template, kwargs)
- self.db_path = _get_db_path(db_path, use_temp, use_memory)
+ self.db_path = _get_sqlite_cache_path(
+ db_path, use_cache_dir=use_cache_dir, use_temp=use_temp, use_memory=use_memory
+ )
self.fast_save = fast_save
self.table_name = table_name
@@ -336,27 +344,39 @@ def _format_sequence(values: Collection) -> Tuple[str, List]:
return ','.join(['?'] * len(values)), list(values)
-def _get_db_path(db_path: Union[Path, str], use_temp: bool, use_memory: bool) -> str:
- """Get resolved path for database file"""
- db_path = str(db_path)
+def _get_sqlite_cache_path(
+ db_path: Union[Path, str], use_cache_dir: bool, use_temp: bool, use_memory: bool = False
+) -> str:
+ """Get a resolved path for a SQLite database file (or memory URI("""
# Use an in-memory database, if specified
+ db_path = str(db_path)
if use_memory:
return MEMORY_URI
elif ':memory:' in db_path or 'mode=memory' in db_path:
return db_path
- # Save to a temp directory, if specified
- if use_temp and not isabs(db_path):
- db_path = join(gettempdir(), db_path)
-
- # Expand relative and user paths (~/*), and add file extension if not specified
- db_path = abspath(expanduser(db_path))
+ # Add file extension if not specified
if '.' not in basename(db_path):
db_path += '.sqlite'
+ return get_cache_path(db_path, use_cache_dir, use_temp)
+
+
+def get_cache_path(
+ db_path: Union[Path, str], use_cache_dir: bool = False, use_temp: bool = False
+) -> str:
+ """Get a resolved cache path"""
+ db_path = str(db_path)
+
+ # Save to platform-specific temp or user cache directory, if specified
+ if use_cache_dir and not isabs(db_path):
+ db_path = join(user_cache_dir(), db_path)
+ elif use_temp and not isabs(db_path):
+ db_path = join(gettempdir(), db_path)
- # Make sure parent dirs exist
+ # Expand relative and user paths (~/*), and make sure parent dirs exist
+ db_path = abspath(expanduser(db_path))
makedirs(dirname(db_path), exist_ok=True)
- return db_path
+ return str(db_path)
def sqlite_template(
diff --git a/tests/integration/test_filesystem.py b/tests/integration/test_filesystem.py
index c1061c1..3a60190 100644
--- a/tests/integration/test_filesystem.py
+++ b/tests/integration/test_filesystem.py
@@ -4,6 +4,7 @@ from shutil import rmtree
from tempfile import gettempdir
import pytest
+from appdirs import user_cache_dir
from requests_cache.backends import FileCache, FileDict
from requests_cache.serializers import SERIALIZERS, SerializerPipeline
@@ -24,6 +25,12 @@ class TestFileDict(BaseStorageTest):
cache.clear()
return cache
+ def test_use_cache_dir(self):
+ relative_path = self.storage_class(CACHE_NAME).cache_dir
+ cache_dir_path = self.storage_class(CACHE_NAME, use_cache_dir=True).cache_dir
+ assert not relative_path.startswith(user_cache_dir())
+ assert cache_dir_path.startswith(user_cache_dir())
+
def test_use_temp(self):
relative_path = self.storage_class(CACHE_NAME).cache_dir
temp_path = self.storage_class(CACHE_NAME, use_temp=True).cache_dir
diff --git a/tests/integration/test_sqlite.py b/tests/integration/test_sqlite.py
index c0f83e3..c7107e8 100644
--- a/tests/integration/test_sqlite.py
+++ b/tests/integration/test_sqlite.py
@@ -3,6 +3,8 @@ from tempfile import gettempdir
from threading import Thread
from unittest.mock import patch
+from appdirs import user_cache_dir
+
from requests_cache.backends.base import BaseCache
from requests_cache.backends.sqlite import MEMORY_URI, SQLiteCache, SQLiteDict, SQLitePickleDict
from tests.integration.base_cache_test import BaseCacheTest
@@ -19,6 +21,12 @@ class SQLiteTestCase(BaseStorageTest):
except Exception:
pass
+ def test_use_cache_dir(self):
+ relative_path = self.storage_class(CACHE_NAME).db_path
+ cache_dir_path = self.storage_class(CACHE_NAME, use_cache_dir=True).db_path
+ assert not relative_path.startswith(user_cache_dir())
+ assert cache_dir_path.startswith(user_cache_dir())
+
def test_use_temp(self):
relative_path = self.storage_class(CACHE_NAME).db_path
temp_path = self.storage_class(CACHE_NAME, use_temp=True).db_path