Skip to content

Commit

Permalink
Merge pull request #165 from requests-cache/forge
Browse files Browse the repository at this point in the history
Remove most usage of python-forge and make it a doc dependency only
  • Loading branch information
JWCook authored Jul 23, 2023
2 parents 07894b4 + 75204bc commit 8668e7d
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 361 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ jobs:
- 80:80

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- uses: snok/[email protected]
Expand Down Expand Up @@ -71,8 +71,8 @@ jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ env.LATEST_PY_VERSION }}
- name: Run style checks and linting via pre-commit hooks
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ env.LATEST_PY_VERSION }}
- uses: snok/[email protected]
Expand Down
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
## 0.8.3 (2023-07-TBD)
* Add `autoclose` option to `CacheBackend` to close backend connections when the session context exits.
* Enabled by default for SQLite backend, and disabled by default for other backends.
* `python-forge` is no longer required and is now an optional dependency

## 0.8.2 (2023-07-14)
* Add some missing type annotations to backend classes
Expand Down
15 changes: 5 additions & 10 deletions aiohttp_client_cache/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from aiohttp_client_cache.cache_control import CacheActions, ExpirationPatterns, ExpirationTime
from aiohttp_client_cache.cache_keys import create_key
from aiohttp_client_cache.response import AnyResponse, CachedResponse
from aiohttp_client_cache.signatures import extend_init_signature

ResponseOrKey = Union[CachedResponse, bytes, str, None]
_FilterFn = Union[
Expand Down Expand Up @@ -266,6 +265,11 @@ async def close_if_enabled(self):
class BaseCache(metaclass=ABCMeta):
"""A wrapper for lower-level cache storage operations. This is separate from
:py:class:`.CacheBackend` to allow a single backend to contain multiple cache objects.
Args:
secret_key: Optional secret key used to sign cache items for added security
salt: Optional salt used to sign cache items
serializer: Custom serializer that provides ``loads`` and ``dumps`` methods
"""

def __init__(
Expand All @@ -275,12 +279,6 @@ def __init__(
serializer=None,
**kwargs,
):
"""
Args:
secret_key: Optional secret key used to sign cache items for added security
salt: Optional salt used to sign cache items
serializer: Custom serializer that provides ``loads`` and ``dumps`` methods
"""
super().__init__()
self._serializer = serializer or self._get_serializer(secret_key, salt)

Expand Down Expand Up @@ -359,9 +357,6 @@ async def pop(self, key: str, default=None) -> ResponseOrKey:
return default


CacheBackend = extend_init_signature(BaseCache)(CacheBackend) # type: ignore


class DictCache(BaseCache, UserDict):
"""Simple in-memory storage that wraps a dict with the :py:class:`.BaseStorage` interface"""

Expand Down
30 changes: 15 additions & 15 deletions aiohttp_client_cache/backends/dynamodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,26 @@
from botocore.exceptions import ClientError

from aiohttp_client_cache.backends import BaseCache, CacheBackend, ResponseOrKey, get_valid_kwargs
from aiohttp_client_cache.signatures import dynamodb_template, extend_init_signature


@extend_init_signature(CacheBackend, dynamodb_template)
class DynamoDBBackend(CacheBackend):
"""Async cache backend for `DynamoDB <https://aws.amazon.com/dynamodb>`_
(requires `aioboto3 <https://aioboto3.readthedocs.io>`_)
See `DynamoDB Service Resource
<https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#service-resource>`_
for more usage details.
Notes:
* Requires `aioboto3 <https://aioboto3.readthedocs.io>`_
* Accepts keyword arguments for :py:meth:`boto3.session.Session.client`
* See `DynamoDB Service Resource
<https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#service-resource>`_
for more usage details.
Args:
cache_name: Table name to use
key_attr_name: The name of the field to use for keys in the DynamoDB document
val_attr_name: The name of the field to use for values in the DynamoDB document
create_if_not_exists: Whether or not to attempt to create the DynamoDB table
context: An existing `ResourceCreatorContext <https://aioboto3.readthedocs.io/en/latest/usage.html>`_
to reuse instead of creating a new one
kwargs: Additional keyword arguments for :py:class:`.CacheBackend` or backend connection
"""

def __init__(
Expand All @@ -29,15 +38,6 @@ def __init__(
context: ResourceCreatorContext = None,
**kwargs: Any,
):
"""
Args:
cache_name: Table name to use
key_attr_name: The name of the field to use for keys in the DynamoDB document
val_attr_name: The name of the field to use for values in the DynamoDB document
create_if_not_exists: Whether or not to attempt to create the DynamoDB table
context: An existing `ResourceCreatorContext <https://aioboto3.readthedocs.io/en/latest/usage.html>`_
to reuse instead of creating a new one
"""
super().__init__(cache_name=cache_name, **kwargs)
self.responses = DynamoDbCache(
cache_name,
Expand Down
8 changes: 6 additions & 2 deletions aiohttp_client_cache/backends/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@

class FileBackend(CacheBackend):
"""Backend that stores cached responses as files on the local filesystem.
Response paths will be in the format ``<cache_name>/responses/<cache_key>``.
Redirects are stored in a SQLite database, located at ``<cache_name>/redirects.sqlite``.
Notes:
* Requires `aiofiles <https://github.com/Tinche/aiofiles>`_
* Response paths will be in the format ``<cache_name>/responses/<cache_key>``.
* Redirects are stored in a SQLite database, located at ``<cache_name>/redirects.sqlite``.
Args:
cache_name: Base directory for cache files
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.
kwargs: Additional keyword arguments for :py:class:`.CacheBackend`
"""

def __init__(
Expand Down
17 changes: 9 additions & 8 deletions aiohttp_client_cache/backends/mongodb.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@
from pymongo import MongoClient

from aiohttp_client_cache.backends import BaseCache, CacheBackend, ResponseOrKey, get_valid_kwargs
from aiohttp_client_cache.signatures import extend_init_signature, mongo_template


@extend_init_signature(CacheBackend, mongo_template)
class MongoDBBackend(CacheBackend):
"""Async cache backend for `MongoDB <https://www.mongodb.com>`_
(requires `motor <https://motor.readthedocs.io>`_)
Notes:
* Requires `motor <https://motor.readthedocs.io>`_
* Accepts keyword arguments for :py:class:`pymongo.MongoClient`
Args:
cache_name: Database name
connection: Optional client object to use instead of creating a new one
kwargs: Additional keyword arguments for :py:class:`.CacheBackend` or backend connection
"""

def __init__(
Expand All @@ -19,11 +25,6 @@ def __init__(
connection: AsyncIOMotorClient = None,
**kwargs: Any
):
"""
Args:
cache_name: Database name
connection: Optional client object to use instead of creating a new one
"""
super().__init__(cache_name=cache_name, **kwargs)
self.responses = MongoDBPickleCache(cache_name, 'responses', connection, **kwargs)
self.redirects = MongoDBCache(cache_name, 'redirects', self.responses.connection, **kwargs)
Expand Down
21 changes: 11 additions & 10 deletions aiohttp_client_cache/backends/redis.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
from typing import Any, AsyncIterable, Optional

from redis.asyncio import Connection, Redis, from_url
from redis.asyncio import Redis, from_url

from aiohttp_client_cache.backends import BaseCache, CacheBackend, ResponseOrKey, get_valid_kwargs
from aiohttp_client_cache.signatures import extend_init_signature, redis_template

DEFAULT_ADDRESS = 'redis://localhost'


@extend_init_signature(CacheBackend, redis_template)
class RedisBackend(CacheBackend):
"""Async cache backend for `Redis <https://redis.io>`_
(requires `redis-py <https://redis-py.readthedocs.io>`_)
Notes:
* Requires `redis-py <https://redis-py.readthedocs.io>`_
* Accepts keyword arguments for :py:class:`redis.asyncio.client.Redis`
Args:
cache_name: Used as a namespace (prefix for hash key)
address: Redis server URI
kwargs: Additional keyword arguments for :py:class:`.CacheBackend` or backend connection
"""

def __init__(
self, cache_name: str = 'aiohttp-cache', address: str = DEFAULT_ADDRESS, **kwargs: Any
):
"""
Args:
cache_name: Used as a namespace (prefix for hash key)
address: Redis server URI
"""
super().__init__(cache_name=cache_name, **kwargs)
self.responses = RedisCache(cache_name, 'responses', address=address, **kwargs)
self.redirects = RedisCache(cache_name, 'redirects', address=address, **kwargs)
Expand Down Expand Up @@ -52,7 +53,7 @@ def __init__(
super().__init__(**kwargs)
self.address = address
self._connection = connection
self.connection_kwargs = get_valid_kwargs(Connection.__init__, kwargs)
self.connection_kwargs = get_valid_kwargs(Redis.__init__, kwargs)
self.hash_key = f'{namespace}:{collection_name}'

async def get_connection(self):
Expand Down
34 changes: 25 additions & 9 deletions aiohttp_client_cache/backends/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,33 @@
from os.path import abspath, basename, dirname, expanduser, isabs, join
from pathlib import Path
from tempfile import gettempdir
from typing import Any, AsyncIterable, AsyncIterator, Optional, Union
from typing import Any, AsyncIterable, AsyncIterator, Optional, Type, Union

import aiosqlite

from aiohttp_client_cache.backends import BaseCache, CacheBackend, ResponseOrKey, get_valid_kwargs
from aiohttp_client_cache.signatures import sqlite_template

bulk_commit_var: ContextVar[bool] = ContextVar('bulk_commit', default=False)


class SQLiteBackend(CacheBackend):
"""Async cache backend for `SQLite <https://www.sqlite.org>`_
(requires `aiosqlite <https://aiosqlite.omnilib.dev>`_)
The path to the database file will be ``<cache_name>`` (or ``<cache_name>.sqlite`` if no file
extension is specified)
Notes:
* Requires `aiosqlite <https://aiosqlite.omnilib.dev>`_
* Accepts keyword arguments for :py:func:`sqlite3.connect` / :py:func:`aiosqlite.connect`
* The path to the database file will be ``<cache_name>`` (or ``<cache_name>.sqlite`` if no
file extension is specified)
Args:
cache_name: Database filename
use_temp: Store database in a temp directory (e.g., ``/tmp/http_cache.sqlite``).
Note: if ``cache_name`` is an absolute path, this option will be ignored.
fast_save: Increas cache write performance, but with the possibility of data loss. See
`pragma: synchronous <http://www.sqlite.org/pragma.html#pragma_synchronous>`_ for details.
use_temp: Store database in a temp directory (e.g., ``/tmp/http_cache.sqlite``).
Note: if ``cache_name`` is an absolute path, this option will be ignored.
fast_save: Increase cache write performance, but with the possibility of data loss. See
`pragma: synchronous <http://www.sqlite.org/pragma.html#pragma_synchronous>`_ for
details.
autoclose: Close any active backend connections when the session is closed
kwargs: Additional keyword arguments for :py:class:`.CacheBackend` or backend connection
"""

def __init__(
Expand Down Expand Up @@ -198,6 +202,18 @@ async def write(self, key, item):
await super().write(key, sqlite3.Binary(self.serialize(item)))


def sqlite_template(
timeout: float = 5.0,
detect_types: int = 0,
isolation_level: Optional[str] = None,
check_same_thread: bool = True,
factory: Optional[Type] = None,
cached_statements: int = 100,
uri: bool = False,
):
"""Template function to get an accurate function signature for :py:func:`sqlite3.connect`"""


def _get_cache_filename(filename: Union[Path, str], use_temp: bool) -> str:
"""Get resolved path for database file"""
# Save to a temp directory, if specified
Expand Down
Loading

0 comments on commit 8668e7d

Please sign in to comment.