Skip to content

Commit

Permalink
Include example scripts on readthedocs, and move some more details fr…
Browse files Browse the repository at this point in the history
…om Readme to readthedocs
  • Loading branch information
JWCook committed Apr 9, 2021
1 parent f498d0c commit be00ba8
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 69 deletions.
88 changes: 30 additions & 58 deletions README.md
Expand Up @@ -12,39 +12,36 @@ client requests.

See full documentation at https://aiohttp-client-cache.readthedocs.io

## Features
# Features
* **Ease of use:** Use as a [drop-in replacement](https://aiohttp-client-cache.readthedocs.io/en/latest/user_guide.html)
for `aiohttp.ClientSession`
* **Customization:** Works out of the box with zero config, but with plenty of options available
for customizing cache
* **Customization:** Works out of the box with little to no config, but with plenty of options
available for customizing cache
[expiration](https://aiohttp-client-cache.readthedocs.io/en/latest/user_guide.html#cache-expiration)
and other [behavior](https://aiohttp-client-cache.readthedocs.io/en/latest/user_guide.html#cache-options)
* **Persistence:** Includes several [storage backends](https://aiohttp-client-cache.readthedocs.io/en/latest/backends.html):
SQLite, DynamoDB, MongoDB, and Redis.

## Development Status
**This is an early work in progress!**
# Development Status
**This library is a work in progress!**

Bugs are likely, and breaking changes should be expected until a `1.0` release, so version pinning
is recommended.
Breaking changes should be expected until a `1.0` release, so version pinning is recommended.

I am developing this while also maintaining [requests-cache](https://github.com/reclosedev/requests-cache),
and my eventual goal is to have a similar (but not identical) feature set between the two libraries.
If there is a specific feature you want that aiohttp-client-cache doesn't yet have, please create an
issue to request it!
and my goal is to eventually have a similar (but not identical) feature set between the two libraries.
If there is a feature you want, or if you've discovered a bug, of it you have other general feedback, please
[create an issue](https://github.com/JWCook/aiohttp-client-cache/issues/new/choose) for it!

# Quickstart
Requires python 3.7+

First, install with pip:
First, install with pip (python 3.7+ required):
```bash
pip install aiohttp-client-cache
````
```

## Basic Usage
Next, use [aiohttp_client_cache.CachedSession](https://aiohttp-client-cache.readthedocs.io/en/latest/modules/aiohttp_client_cache.session.html#aiohttp_client_cache.session.CachedSession)
in place of [aiohttp.ClientSession](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession)
to send and cache requests. To quickly demonstrate how to use it:
in place of [aiohttp.ClientSession](https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession).
To briefly demonstrate how to use it:

**Replace this:**
```python
Expand All @@ -63,55 +60,30 @@ async with CachedSession(cache=SQLiteBackend('demo_cache')) as session:
```

The URL in this example adds a delay of 1 second, simulating a slow or rate-limited website.
With caching, the response will be fetched once, saved to `demo_cache.sqlite`, and subsequent
With caching, the response will be fetched once, saved to `demo_cache.sqlite`, and subsequent
requests will return the cached response near-instantly.

## Customized Caching
Several options are available to customize caching behavior. This example demostrates a few of them:
## Configuration
Several options are available to customize caching behavior. This example demonstrates a few of them:

```python
import asyncio
from datetime import timedelta
from aiohttp_client_cache import CachedSession, SQLiteBackend
from aiohttp_client_cache import SQLiteBackend

cache = SQLiteBackend(
cache_name='~/.cache/aiohttp-requests.db', # For SQLite, this will be used as the filename
expire_after=60*60, # By default, cached responses expire in an hour
urls_expire_after={
'httpbin.org/image': timedelta(days=7), # Requests for this base URL with expire in a week
'*.fillmurray.com': -1, # Requests matching this pattern will never expire
},
ignored_params=['auth_token'], # Ignore this param when caching responses
urls_expire_after={'*.fillmurray.com': -1}, # Requests for any subdomain on this site will never expire
allowed_codes=(200, 418), # Cache responses with these status codes
allowed_methods=('GET', 'POST'), # Cache requests with these HTTP methods
include_headers=True, # Cache requests with different headers separately
ignored_params=['auth_token'], # Keep using the cached response even if this param changes
timeout=2.5, # Connection timeout for SQLite backend
)
async with CachedSession(cache=cache) as session:
urls = [
'https://httpbin.org/get', # Expires in an hour
'https://httpbin.org/image/jpeg', # Expires in a week
'http://www.fillmurray.com/460/300', # Never expires
]
tasks = [asyncio.create_task(session.get(url)) for url in urls]
responses = await asyncio.gather(*tasks)
```
See [CacheBackend](https://aiohttp-client-cache.readthedocs.io/en/latest/modules/aiohttp_client_cache.backends.base.html#aiohttp_client_cache.backends.base.CacheBackend)
documentation for more usage details.
## Next Steps
To find out more, see:
* The [User Guide](https://aiohttp-client-cache.readthedocs.io/en/latest/user_guide.html) section
* The [API Reference](https://aiohttp-client-cache.readthedocs.io/en/latest/reference.html) section
* More examples in the [examples/](https://github.com/JWCook/aiohttp-client-cache/blob/main/examples)
folder
## Related Projects
Other python cache projects you may want to check out:

* [aiohttp-cache](https://github.com/cr0hn/aiohttp-cache): A server-side async HTTP cache for the
`aiohttp` web server
* [diskcache](https://github.com/grantjenks/python-diskcache): A general-purpose (not HTTP-specific)
file-based cache built on SQLite
* [aiocache](https://github.com/aio-libs/aiocache): General-purpose (not HTTP-specific) async cache
backends
* [requests-cache](https://github.com/reclosedev/requests-cache) An HTTP cache for the `requests` library
* [CacheControl](https://github.com/ionrock/cachecontrol): An HTTP cache for `requests` that caches
according to uses HTTP headers and status codes
# More Info
To learn more, see:
* [User Guide](https://aiohttp-client-cache.readthedocs.io/en/latest/user_guide.html)
* [Cache Backends](https://aiohttp-client-cache.readthedocs.io/en/latest/backends.html)
* [API Reference](https://aiohttp-client-cache.readthedocs.io/en/latest/reference.html)
* [Examples](https://aiohttp-client-cache.readthedocs.io/en/latest/examples.html)
2 changes: 1 addition & 1 deletion aiohttp_client_cache/backends/base.py
Expand Up @@ -50,7 +50,7 @@ def __init__(
urls_expire_after: Expiration times to apply for different URL patterns
allowed_codes: Only cache responses with these status codes
allowed_methods: Only cache requests with these HTTP methods
include_headers: Make request headers part of the cache key
include_headers: Cache requests with different headers separately
ignored_params: Request parameters to be excluded from the cache key
filter_fn: function that takes a :py:class:`aiohttp.ClientResponse` object and
returns a boolean indicating whether or not that response should be cached. Will be
Expand Down
1 change: 1 addition & 0 deletions aiohttp_client_cache/session.py
Expand Up @@ -16,6 +16,7 @@

class CacheMixin:
"""A mixin class for :py:class:`aiohttp.ClientSession` that adds caching support"""

@extend_signature(ClientSession.__init__)
def __init__(self, *, cache: CacheBackend = None, **kwargs):
super().__init__(**kwargs) # type: ignore
Expand Down
26 changes: 26 additions & 0 deletions docs/_static/collapsible_container.css
@@ -0,0 +1,26 @@
/* Taken from: https://github.com/plone/training/blob/master/_static/custom.css */

.toggle {
background: none repeat scroll 0 0 #e7f2fa;
padding: 12px;
line-height: 24px;
margin-bottom: 24px;
}

.toggle .admonition-title {
display: block;
clear: both;
cursor: pointer;
}

.toggle .admonition-title:after {
content: " ▶";
}

.toggle .admonition-title.open:after {
content: " ▼";
}

.toggle p:last-child {
margin-bottom: 0;
}
15 changes: 15 additions & 0 deletions docs/_templates/page.html
@@ -0,0 +1,15 @@
{# Taken from: https://github.com/plone/training/blob/master/_templates/page.html #}
{% extends "!page.html" %}

{% block footer %}
<script type="text/javascript">
$(document).ready(function() {
$(".toggle > *").hide();
$(".toggle .admonition-title").show();
$(".toggle .admonition-title").click(function() {
$(this).parent().children().not(".admonition-title").toggle(400);
$(this).parent().children(".admonition-title").toggleClass("open");
})
});
</script>
{% endblock %}
1 change: 1 addition & 0 deletions docs/conf.py
Expand Up @@ -108,6 +108,7 @@
def setup(app):
"""Run some additional steps after the Sphinx builder is initialized"""
app.connect('builder-inited', patch_automodapi)
app.add_css_file('collapsible_container.css')


def patch_automodapi(app):
Expand Down
29 changes: 29 additions & 0 deletions docs/examples.rst
@@ -0,0 +1,29 @@
Examples
--------
Following are some complete examples to demonstrate some of the features of aiohttp-client-cache.
These can also be found in the
`examples/ <https://github.com/JWCook/aiohttp-client-cache/tree/main/examples>`_ folder on GitHub.

Expiration based on URL patterns
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: ../examples/url_patterns.py
:start-line: 3
:end-line: 4

.. admonition:: Example code
:class: toggle

.. literalinclude:: ../examples/url_patterns.py
:lines: 1,5-

Precaching site links
~~~~~~~~~~~~~~~~~~~~~
.. include:: ../examples/precache.py
:start-line: 2
:end-line: 18

.. admonition:: Example code
:class: toggle

.. literalinclude:: ../examples/precache.py
:lines: 1,20-
11 changes: 6 additions & 5 deletions docs/index.rst
@@ -1,12 +1,12 @@
.. _index-page:

.. Omit README link to ReadTheDocs, since we're already on ReadTheDocs!
.. Omit links to ReadTheDocs, since we're already on ReadTheDocs
.. mdinclude:: ../README.md
:end-line: 15
:end-line: 12

.. mdinclude:: ../README.md
:start-line: 17

:start-line: 14
:end-line: 83

Contents
========
Expand All @@ -17,12 +17,13 @@ Contents
user_guide
backends
security
examples
reference
related_projects
contributing
contributors
history


Indices and tables
==================

Expand Down
13 changes: 13 additions & 0 deletions docs/related_projects.rst
@@ -0,0 +1,13 @@
Related Projects
----------------
Other python cache projects you may want to check out:

* `aiohttp-cache <https://github.com/cr0hn/aiohttp-cache>`_: A server-side async HTTP cache for the
``aiohttp`` web server
* `diskcache <https://github.com/grantjenks/python-diskcache>`_: A general-purpose (not HTTP-specific)
file-based cache built on SQLite
* `aiocache <https://github.com/aio-libs/aiocache>`_: General-purpose (not HTTP-specific) async cache
backends
* `requests-cache <https://github.com/reclosedev/requests-cache`_: An HTTP cache for the ``requests`` library
* `CacheControl <https://github.com/ionrock/cachecontrol>`_: An HTTP cache for ``requests`` that caches
according to uses HTTP headers and status codes
10 changes: 5 additions & 5 deletions examples/precache.py
@@ -1,12 +1,12 @@
#!/usr/bin/env python3
"""A contrived example of using aiohttp + caching.
Fetches and caches the content of a given web page and all links found on that page
"""
An example that fetches and caches the content of a given web page, and all links found on that page
Usage::
Usage: ``./precache.py <url>``
./precache.py <url>
Example:
Example::
.. code-block:: bash
$ # Run twice and note stats before and after
$ ./precache.py https://www.nytimes.com
Expand Down
40 changes: 40 additions & 0 deletions examples/url_patterns.py
@@ -0,0 +1,40 @@
#!/usr/bin/env python3
# fmt: off
"""
An example of setting expiration based on :ref:`user_guide:url patterns`
"""
import asyncio
from datetime import timedelta

from aiohttp_client_cache import CachedSession, SQLiteBackend

default_expire_after = 60 * 60 # By default, cached responses expire in an hour
urls_expire_after = {
'httpbin.org/image': timedelta(days=7), # Requests for this base URL will expire in a week
'*.fillmurray.com': -1, # Requests matching this pattern will never expire
}
urls = [
'https://httpbin.org/get', # Will expire in an hour
'https://httpbin.org/image/jpeg', # Will expire in a week
'http://www.fillmurray.com/460/300', # Will never expire
]


async def main():
cache = SQLiteBackend(
cache_name='~/.cache/aiohttp-requests.db',
expire_after=default_expire_after,
urls_expire_after=urls_expire_after,
)

async with CachedSession(cache=cache) as session:
tasks = [asyncio.create_task(session.get(url)) for url in urls]
return await asyncio.gather(*tasks)


if __name__ == "__main__":
original_responses = asyncio.run(main())
cached_responses = asyncio.run(main())
for response in cached_responses:
expires = response.expires.isoformat() if response.expires else 'Never'
print(f'{response.url}: {expires}')

0 comments on commit be00ba8

Please sign in to comment.