## 1. Project Overview & Quickstart (jazzband/django-redis) ## File: README.rst ============================== Redis cache backend for Django ============================== .. image:: https://jazzband.co/static/img/badge.svg :target: https://jazzband.co/ :alt: Jazzband .. image:: https://github.com/jazzband/django-redis/actions/workflows/ci.yml/badge.svg :target: https://github.com/jazzband/django-redis/actions/workflows/ci.yml :alt: GitHub Actions .. image:: https://codecov.io/gh/jazzband/django-redis/branch/master/graph/badge.svg :target: https://codecov.io/gh/jazzband/django-redis :alt: Coverage .. image:: https://img.shields.io/pypi/v/django-redis.svg?style=flat :target: https://pypi.org/project/django-redis/ This is a `Jazzband `_ project. By contributing you agree to abide by the `Contributor Code of Conduct `_ and follow the `guidelines `_. Introduction ------------ django-redis is a BSD licensed, full featured Redis cache and session backend for Django. Why use django-redis? ~~~~~~~~~~~~~~~~~~~~~ - Uses native redis-py url notation connection strings - Pluggable clients - Pluggable parsers - Pluggable serializers - Primary/secondary support in the default client - Comprehensive test suite - Used in production in several projects as cache and session storage - Supports infinite timeouts - Facilities for raw access to Redis client/connection pool - Highly configurable (can emulate memcached exception behavior, for example) - Unix sockets supported by default Requirements ~~~~~~~~~~~~ - `Python`_ 3.10+ - `Django`_ 5.2+ - `redis-py`_ 4.0.2+ - `Redis server`_ 2.8+ .. _Python: https://www.python.org/downloads/ .. _Django: https://www.djangoproject.com/download/ .. _redis-py: https://pypi.org/project/redis/ .. _Redis server: https://redis.io/download User guide ---------- Installation ~~~~~~~~~~~~ Install with pip: .. code-block:: console $ python -m pip install django-redis Configure as cache backend ~~~~~~~~~~~~~~~~~~~~~~~~~~ To start using django-redis, you should change your Django cache settings to something like: .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", } } django-redis uses the redis-py native URL notation for connection strings, it allows better interoperability and has a connection string in more "standard" way. Some examples: - ``redis://[[username]:[password]]@localhost:6379/0`` - ``rediss://[[username]:[password]]@localhost:6379/0`` - ``unix://[[username]:[password]]@/path/to/socket.sock?db=0`` Three URL schemes are supported: - ``redis://``: creates a normal TCP socket connection - ``rediss://``: creates a SSL wrapped TCP socket connection - ``unix://`` creates a Unix Domain Socket connection There are several ways to specify a database number: - A ``db`` querystring option, e.g. ``redis://localhost?db=0`` - If using the ``redis://`` scheme, the path argument of the URL, e.g. ``redis://localhost/0`` When using `Redis' ACLs `_, you will need to add the username and the password in the connection string or in ``OPTIONS`` with the keys ``USERNAME`` and ``PASSWORD``. *NOTE: Values in the connection string have precedence!* The login for the user ``django`` would look like this: .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://django:mysecret@localhost:6379/0", } } Instead you may specify both of these values in ``OPTIONS``: .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://localhost:6379/0", "OPTIONS": { "USERNAME": "django", "PASSWORD": "mysecret", } } } And, finally you may mix the two as follows (be sure not to include a password, even if blank in the connection string): .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://django@localhost:6379/0", "OPTIONS": {"PASSWORD": "mysecret"} } } Configure as session backend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django can by default use any cache backend as session backend and you benefit from that by using django-redis as backend for session storage without installing any additional backends: .. code-block:: python SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default" Testing with django-redis ~~~~~~~~~~~~~~~~~~~~~~~~~ django-redis supports customizing the underlying Redis client (see "Pluggable clients"). This can be used for testing purposes. In case you want to flush all data from the cache after a test, add the following lines to your test class: .. code-block:: python from django_redis import get_redis_connection def tearDown(self): get_redis_connection("default").flushall() Advanced usage -------------- Pickle version ~~~~~~~~~~~~~~ For almost all values, django-redis uses pickle to serialize objects. The ``pickle.DEFAULT_PROTOCOL`` version of pickle is used by default to ensure safe upgrades and compatibility across Python versions. If you want set a concrete version, you can do it, using ``PICKLE_VERSION`` option: .. code-block:: python CACHES = { "default": { # ... "OPTIONS": { "PICKLE_VERSION": -1 # Will use highest protocol version available } } } Socket timeout ~~~~~~~~~~~~~~ Socket timeout can be set using ``SOCKET_TIMEOUT`` and ``SOCKET_CONNECT_TIMEOUT`` options: .. code-block:: python CACHES = { "default": { # ... "OPTIONS": { "SOCKET_CONNECT_TIMEOUT": 5, # seconds "SOCKET_TIMEOUT": 5, # seconds } } } ``SOCKET_CONNECT_TIMEOUT`` is the timeout for the connection to be established and ``SOCKET_TIMEOUT`` is the timeout for read and write operations after the connection is established. Compression support ~~~~~~~~~~~~~~~~~~~ django-redis comes with compression support out of the box, but is deactivated by default. You can activate it setting up a concrete backend: .. code-block:: python CACHES = { "default": { # ... "OPTIONS": { "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor", } } } Let see an example, of how make it work with *lzma* compression format: .. code-block:: python import lzma CACHES = { "default": { # ... "OPTIONS": { "COMPRESSOR": "django_redis.compressors.lzma.LzmaCompressor", } } } *Lz4* compression support (requires the lz4 library): .. code-block:: python import lz4 CACHES = { "default": { # ... "OPTIONS": { "COMPRESSOR": "django_redis.compressors.lz4.Lz4Compressor", } } } *Zstandard (zstd)* compression support (requires the pyzstd library): .. code-block:: python import pyzstd CACHES = { "default": { # ... "OPTIONS": { "COMPRESSOR": "django_redis.compressors.zstd.ZStdCompressor", } } } *Gzip* compression support: .. code-block:: python import gzip CACHES = { "default": { # ... "OPTIONS": { "COMPRESSOR": "django_redis.compressors.gzip.GzipCompressor", } } } Memcached exceptions behavior ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some situations, when Redis is only used for cache, you do not want exceptions when Redis is down. This is default behavior in the memcached backend and it can be emulated in django-redis. For setup memcached like behaviour (ignore connection exceptions), you should set ``IGNORE_EXCEPTIONS`` settings on your cache configuration: .. code-block:: python CACHES = { "default": { # ... "OPTIONS": { "IGNORE_EXCEPTIONS": True, } } } Also, you can apply the same settings to all configured caches, you can set the global flag in your settings: .. code-block:: python DJANGO_REDIS_IGNORE_EXCEPTIONS = True Log Ignored Exceptions ~~~~~~~~~~~~~~~~~~~~~~ When ignoring exceptions with ``IGNORE_EXCEPTIONS`` or ``DJANGO_REDIS_IGNORE_EXCEPTIONS``, you may optionally log exceptions using the global variable ``DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS`` in your settings file:: DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True If you wish to specify the logger in which the exceptions are output, simply set the global variable ``DJANGO_REDIS_LOGGER`` to the string name and/or path of the desired logger. This will default to ``__name__`` if no logger is specified and ``DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS`` is ``True``:: DJANGO_REDIS_LOGGER = 'some.specified.logger' Infinite timeout ~~~~~~~~~~~~~~~~ django-redis comes with infinite timeouts support out of the box. And it behaves in same way as django backend contract specifies: - ``timeout=0`` expires the value immediately. - ``timeout=None`` infinite timeout .. code-block:: python cache.set("key", "value", timeout=None) Get ttl (time-to-live) from key ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With Redis, you can access to ttl of any stored key, for it, django-redis exposes ``ttl`` function. It returns: - 0 if key does not exists (or already expired). - None for keys that exists but does not have any expiration. - ttl value for any volatile key (any key that has expiration). .. code-block:: pycon >>> from django.core.cache import cache >>> cache.set("foo", "value", timeout=25) >>> cache.ttl("foo") 25 >>> cache.ttl("not-existent") 0 With Redis, you can access to ttl of any stored key in milliseconds, for it, django-redis exposes ``pttl`` function. .. code-block:: pycon >>> from django.core.cache import cache >>> cache.set("foo", "value", timeout=25) >>> cache.pttl("foo") 25000 >>> cache.pttl("not-existent") 0 Expire & Persist ~~~~~~~~~~~~~~~~ Additionally to the simple ttl query, you can send persist a concrete key or specify a new expiration timeout using the ``persist`` and ``expire`` methods: .. code-block:: pycon >>> cache.set("foo", "bar", timeout=22) >>> cache.ttl("foo") 22 >>> cache.persist("foo") True >>> cache.ttl("foo") None .. code-block:: pycon >>> cache.set("foo", "bar", timeout=22) >>> cache.expire("foo", timeout=5) True >>> cache.ttl("foo") 5 The ``expire_at`` method can be used to make the key expire at a specific moment in time. .. code-block:: pycon >>> cache.set("foo", "bar", timeout=22) >>> cache.expire_at("foo", datetime.now() + timedelta(hours=1)) True >>> cache.ttl("foo") 3600 The ``pexpire_at`` method can be used to make the key expire at a specific moment in time with milliseconds precision: .. code-block:: pycon >>> cache.set("foo", "bar", timeout=22) >>> cache.pexpire_at("foo", datetime.now() + timedelta(milliseconds=900, hours=1)) True >>> cache.ttl("foo") 3601 >>> cache.pttl("foo") 3600900 The ``pexpire`` method can be used to provide millisecond precision: .. code-block:: pycon >>> cache.set("foo", "bar", timeout=22) >>> cache.pexpire("foo", timeout=5500) True >>> cache.pttl("foo") 5500 Locks ~~~~~ It also supports the Redis ability to create Redis distributed named locks. The Lock interface is identical to the ``threading.Lock`` so you can use it as replacement. .. code-block:: python with cache.lock("somekey"): do_some_thing() Scan & Delete keys in bulk ~~~~~~~~~~~~~~~~~~~~~~~~~~ django-redis comes with some additional methods that help with searching or deleting keys using glob patterns. .. code-block:: pycon >>> from django.core.cache import cache >>> cache.keys("foo_*") ["foo_1", "foo_2"] A simple search like this will return all matched values. In databases with a large number of keys this isn't suitable method. Instead, you can use the ``iter_keys`` function that works like the ``keys`` function but uses Redis server side cursors. Calling ``iter_keys`` will return a generator that you can then iterate over efficiently. .. code-block:: pycon >>> from django.core.cache import cache >>> cache.iter_keys("foo_*") >>> next(cache.iter_keys("foo_*")) "foo_1" For deleting keys, you should use ``delete_pattern`` which has the same glob pattern syntax as the ``keys`` function and returns the number of deleted keys. .. code-block:: pycon >>> from django.core.cache import cache >>> cache.delete_pattern("foo_*") To achieve the best performance while deleting many keys, you should set ``DJANGO_REDIS_SCAN_ITERSIZE`` to a relatively high number (e.g., 100_000) by default in Django settings or pass it directly to the ``delete_pattern``. .. code-block:: pycon >>> from django.core.cache import cache >>> cache.delete_pattern("foo_*", itersize=100_000) Redis native commands ~~~~~~~~~~~~~~~~~~~~~ django-redis has limited support for some Redis atomic operations, such as the commands ``SETNX`` and ``INCR``. You can use the ``SETNX`` command through the backend ``set()`` method with the ``nx`` parameter: .. code-block:: pycon >>> from django.core.cache import cache >>> cache.set("key", "value1", nx=True) True >>> cache.set("key", "value2", nx=True) False >>> cache.get("key") "value1" Also, the ``incr`` and ``decr`` methods use Redis atomic operations when the value that a key contains is suitable for it. Raw client access ~~~~~~~~~~~~~~~~~ In some situations your application requires access to a raw Redis client to use some advanced features that aren't exposed by the Django cache interface. To avoid storing another setting for creating a raw connection, django-redis exposes functions with which you can obtain a raw client reusing the cache connection string: ``get_redis_connection(alias)``. .. code-block:: pycon >>> from django_redis import get_redis_connection >>> con = get_redis_connection("default") >>> con WARNING: Not all pluggable clients support this feature. Connection pools ~~~~~~~~~~~~~~~~ Behind the scenes, django-redis uses the underlying redis-py connection pool implementation, and exposes a simple way to configure it. Alternatively, you can directly customize a connection/connection pool creation for a backend. The default redis-py behavior is to not close connections, recycling them when possible. Configure default connection pool ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The default connection pool is simple. For example, you can customize the maximum number of connections in the pool by setting ``CONNECTION_POOL_KWARGS`` in the ``CACHES`` setting: .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", # ... "OPTIONS": { "CONNECTION_POOL_KWARGS": {"max_connections": 100} } } } You can verify how many connections the pool has opened with the following snippet: .. code-block:: python from django_redis import get_redis_connection r = get_redis_connection("default") # Use the name you have defined for Redis in settings.CACHES connection_pool = r.connection_pool print("Created connections so far: %d" % connection_pool._created_connections) Since the default connection pool passes all keyword arguments it doesn't use to its connections, you can also customize the connections that the pool makes by adding those options to ``CONNECTION_POOL_KWARGS``: .. code-block:: python CACHES = { "default": { # ... "OPTIONS": { "CONNECTION_POOL_KWARGS": {"max_connections": 100, "retry_on_timeout": True} } } } Use your own connection pool subclass ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sometimes you want to use your own subclass of the connection pool. This is possible with django-redis using the ``CONNECTION_POOL_CLASS`` parameter in the backend options. .. code-block:: python from redis.connection import ConnectionPool class MyOwnPool(ConnectionPool): # Just doing nothing, only for example purpose pass .. code-block:: python # Omitting all backend declaration boilerplate code. "OPTIONS": { "CONNECTION_POOL_CLASS": "myproj.mypool.MyOwnPool", } Customize connection factory ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If none of the previous methods satisfies you, you can get in the middle of the django-redis connection factory process and customize or completely rewrite it. By default, django-redis creates connections through the ``django_redis.pool.ConnectionFactory`` class that is specified in the global Django setting ``DJANGO_REDIS_CONNECTION_FACTORY``. .. code-block:: python class ConnectionFactory(object): def get_connection_pool(self, params: dict): # Given connection parameters in the `params` argument, return new # connection pool. It should be overwritten if you want do # something before/after creating the connection pool, or return # your own connection pool. pass def get_connection(self, params: dict): # Given connection parameters in the `params` argument, return a # new connection. It should be overwritten if you want to do # something before/after creating a new connection. The default # implementation uses `get_connection_pool` to obtain a pool and # create a new connection in the newly obtained pool. pass def get_or_create_connection_pool(self, params: dict): # This is a high layer on top of `get_connection_pool` for # implementing a cache of created connection pools. It should be # overwritten if you want change the default behavior. pass def make_connection_params(self, url: str) -> dict: # The responsibility of this method is to convert basic connection # parameters and other settings to fully connection pool ready # connection parameters. pass def connect(self, url: str): # This is really a public API and entry point for this factory # class. This encapsulates the main logic of creating the # previously mentioned `params` using `make_connection_params` and # creating a new connection using the `get_connection` method. pass Use the sentinel connection factory ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In order to facilitate using `Redis Sentinels`_, django-redis comes with a built in sentinel connection factory, which creates sentinel connection pools. In order to enable this functionality you should add the following: .. code-block:: python # Enable the alternate connection factory. DJANGO_REDIS_CONNECTION_FACTORY = 'django_redis.pool.SentinelConnectionFactory' # These sentinels are shared between all the examples, and are passed # directly to redis Sentinel. These can also be defined inline. SENTINELS = [ ('sentinel-1', 26379), ('sentinel-2', 26379), ('sentinel-3', 26379), ] CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", # The hostname in LOCATION is the primary (service / master) name "LOCATION": "redis://service_name/db", "OPTIONS": { # While the default client will work, this will check you # have configured things correctly, and also create a # primary and replica pool for the service specified by # LOCATION rather than requiring two URLs. "CLIENT_CLASS": "django_redis.client.SentinelClient", # Sentinels which are passed directly to redis Sentinel. "SENTINELS": SENTINELS, # kwargs for redis Sentinel (optional). Example with auth on sentinels "SENTINEL_KWARGS": { "username": "sentinel-user", "password": "sentinel-pass", }, # You can still override the connection pool (optional). "CONNECTION_POOL_CLASS": "redis.sentinel.SentinelConnectionPool", }, }, # A minimal example using the SentinelClient. "minimal": { "BACKEND": "django_redis.cache.RedisCache", # The SentinelClient will use this location for both the primaries # and replicas. "LOCATION": "redis://minimal_service_name/db", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.SentinelClient", "SENTINELS": SENTINELS, }, }, # A minimal example using the DefaultClient. "other": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": [ # The DefaultClient is [primary, replicas...], but with the # SentinelConnectionPool it only requires one "is_master=0". "redis://other_service_name/db?is_master=1", "redis://other_service_name/db?is_master=0", ], "OPTIONS": {"SENTINELS": SENTINELS}, }, # A minimal example only using only replicas in read only mode (and # the DefaultClient). "readonly": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://readonly_service_name/db?is_master=0", "OPTIONS": {"SENTINELS": SENTINELS}, }, } It is also possible to set some caches as sentinels and some as not: .. code-block:: python SENTINELS = [ ('sentinel-1', 26379), ('sentinel-2', 26379), ('sentinel-3', 26379), ] CACHES = { "sentinel": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://service_name/db", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.SentinelClient", "SENTINELS": SENTINELS, "CONNECTION_POOL_CLASS": "redis.sentinel.SentinelConnectionPool", "CONNECTION_FACTORY": "django_redis.pool.SentinelConnectionFactory", }, }, "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", }, }, } .. _Redis Sentinels: https://redis.io/topics/sentinel Pluggable parsers ~~~~~~~~~~~~~~~~~ `redis-py`_, the Python Redis client used by django-redis, will automatically use a C-based parser if the `hiredis`_ package is installed in your environment. This can provide a significant performance boost for parsing Redis replies. To take advantage of this, simply install the `hiredis` package with pip: .. code-block:: console $ python -m pip install hiredis No additional configuration in your Django settings is required. django-redis will use the faster parser automatically. .. _hiredis: https://pypi.org/project/hiredis/ Pluggable clients ~~~~~~~~~~~~~~~~~ django-redis is designed for to be very flexible and very configurable. For it, it exposes a pluggable backends that make easy extend the default behavior, and it comes with few ones out the box. Default client ^^^^^^^^^^^^^^ Almost all about the default client is explained, with one exception: the default client comes with replication support. To connect to a Redis replication setup, you should change the ``LOCATION`` to something like: .. code-block:: python "LOCATION": [ "redis://127.0.0.1:6379/1", "redis://127.0.0.1:6378/1", ] The first connection string represents the primary server and the rest to replica servers. WARNING: Replication setup is not heavily tested in production environments. Shard client ^^^^^^^^^^^^ This pluggable client implements client-side sharding. It inherits almost all functionality from the default client. To use it, change your cache settings to something like this: .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": [ "redis://127.0.0.1:6379/1", "redis://127.0.0.1:6379/2", ], "OPTIONS": { "CLIENT_CLASS": "django_redis.client.ShardClient", } } } WARNING: Shard client is still experimental, so be careful when using it in production environments. Herd client ^^^^^^^^^^^ This pluggable client helps dealing with the thundering herd problem. You can read more about it on link: `Wikipedia `_ Like previous pluggable clients, it inherits all functionality from the default client, adding some additional methods for getting/setting keys. .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.HerdClient", } } } This client exposes additional settings: - ``CACHE_HERD_TIMEOUT``: Set default herd timeout. (Default value: 60s) Pluggable serializer ~~~~~~~~~~~~~~~~~~~~ The pluggable clients serialize data before sending it to the server. By default, django-redis serializes the data using the Python ``pickle`` module. This is very flexible and can handle a large range of object types. To serialize using JSON instead, the serializer ``JSONSerializer`` is also available. .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "SERIALIZER": "django_redis.serializers.json.JSONSerializer", } } } There's also support for serialization using `MsgPack`_ (that requires the msgpack library): .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "SERIALIZER": "django_redis.serializers.msgpack.MSGPackSerializer", } } } .. _MsgPack: https://msgpack.org/ Pluggable Redis client ~~~~~~~~~~~~~~~~~~~~~~ django-redis uses the Redis client ``redis.client.StrictClient`` by default. It is possible to use an alternative client. You can customize the client used by setting ``REDIS_CLIENT_CLASS`` in the ``CACHES`` setting. Optionally, you can provide arguments to this class by setting ``REDIS_CLIENT_KWARGS``. .. code-block:: python CACHES = { "default": { "OPTIONS": { "REDIS_CLIENT_CLASS": "my.module.ClientClass", "REDIS_CLIENT_KWARGS": {"some_setting": True}, } } } Closing Connections ~~~~~~~~~~~~~~~~~~~ The default django-redis behavior on close() is to keep the connections to Redis server. You can change this default behaviour for all caches by the ``DJANGO_REDIS_CLOSE_CONNECTION = True`` in the django settings (globally) or (at cache level) by setting ``CLOSE_CONNECTION: True`` in the ``OPTIONS`` for each configured cache. Setting True as a value will instruct the django-redis to close all the connections (since v. 4.12.2), irrespectively of its current usage. .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CLOSE_CONNECTION": True, } } } SSL/TLS and Self-Signed certificates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In case you encounter a Redis server offering a TLS connection using a self-signed certificate you may disable certification verification with the following: .. code-block:: python CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "rediss://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": {"ssl_cert_reqs": None} } } } License ------- .. code-block:: text Copyright (c) 2011-2015 Andrey Antukh Copyright (c) 2011 Sean Bleier All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS`` AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## 2. Official Technical Reference & Guides (jazzband/website) ## File: README.md [](https://jazzband.co/) [](https://github.com/jazzband/website/actions/workflows/test.yml) [](https://codecov.io/gh/jazzband/website) [](https://calver.org/) The code that renders https://jazzband.co. ## Installation Copy `.env-dist` to `.env`. Install Docker and NPM. Run `make build`. This will create a set of Docker containers with all backends and dependencies. ## Running Get [Orbstack](https://orbstack.dev/). Run `make run` to run the development server and worker. The website will be available at https://jazzband.local. ## License The content of this project is licensed under the [Attribution-NonCommercial-ShareAlike 4.0 International] license, and the underlying source code used to format and display that content is licensed under the MIT license. [add-to-org]: https://github.com/benbalter/add-to-org [Attribution-NonCommercial-ShareAlike 4.0 International]: https://creativecommons.org/licenses/by-nc-sa/4.0/ --- ## File: docs/news/2021/06/04/fiscal-sponsorship.md title: Future of Jazzband tags: django, oss, python published: 2021-06-04T15:41:42+02:00 author: Jannis Leidel author_link: https://twitter.com/jezdez summary: Jazzband is accepted for the Fiscal Sponsorship program of the Python Software Foundation. There were a number of requests to financially support Jazzband over the years and many questions arose around how to continue to grow Jazzband without risking the maintenance of the existing projects. So to support the continued development of Jazzband, an application to the [Fiscal Sponsorship program of the Python Software Foundation][psf-fs] was submitted earlier this year. [psf-fs]: https://www.python.org/psf/fiscal-sponsorees/ And the good news is: **Jazzband has been accepted!** That will allow Jazzband for the first time to receive donations from its individual and corporate users to offset infrastructure cost and work on plans for the future. Here's the donation link: [https://jazzband.co/donate](/donate) --- ## File: docs/news/2021/06/04/project-teams.md title: "Project teams" tags: django, oss, python published: 2021-06-04T12:42:18+02:00 author: Jannis Leidel author_link: https://twitter.com/jezdez summary: Jazzband adds self-service project teams to improve member communication. [Five years ago][launch-blogpost], Jazzband was launched to help Python projects that struggle to continue maintenance for various reasons, e.g. when original authors don't have time anymore to continue the maintenance. [launch-blogpost]: /news/2015/12/17/launching-jazzband Jazzband has grown quite a bit since then: over 1300 people in total have decided to become members over the past 5 years, of which **over 900 current members** remain as of writing this post. At the same time over [50 projects][jazzband-projects] have been transferred to Jazzband and adopted the [Jazzband guidelines][jazzband-guidelines], [Code of Conduct][jazzband-coc] and project maintenance patterns. A handful of projects decided to leave Jazzband again for a number of reasons, which provided plenty of experience for how to improve the Jazzband processes and documentation. It's clear that Jazzband can be better and needs to adapt to the members' needs. One area in particular was brought up often: the communication between those members that are interested in contributing to only specific and not all of the existing [Jazzband projects][jazzband-projects]. So as a first step to fix this: > **Jazzband introduce self-service project teams!** ## What are project teams? Project teams are optional, self-service groups of Jazzband members that are interested in working on specific projects. Project teams are based on [GitHub teams][github-teams] teams that you may already be familiar with. [github-teams]: https://docs.github.com/en/organizations/organizing-members-into-teams/about-teams That means every Jazzband member can show their interest in individual projects by electing to join a project team to further participate in the maintenance of a project. GitHub offers a number of extra features for organization teams that will help to improve a culture of communication and collaboration: - Ability to "mention" a whole team (e.g. "@jazzband/pip-tools") in GitHub's issues and pull-requests - Team discussions for every project team - Ability to request code reviews from whole project teams - More complex per-project code review assignments - Custom team avatars etc. Please remember that team discussions also fall under our [Code of Conduct][jazzband-coc]! ## How can I join a project team? Every Jazzband project has its own dedicated page on the Jazzband website. 1. Go to the [project list](/projects). 2. Select the project you'd like to join to go to its project page. 3. Click the link to join in the **"Interested in becoming a project member?"** box. That's it, your GitHub account was automatically added to the project team on GitHub. ## How can I leave a project team? Leaving a project team is as simple as joining. 1. Go to your [account dashboard](/account). 2. Select the project you'd like to leave from the **"Your projects"** section. 3. Click the link to leave in the **"Thank you for being a project member!"** box. After confirming that you really want to leave, your GitHub account will be automatically removed from the project team on GitHub. ## How do you find team discussions? There are two ways to get to the project team discussions. For both you need to be a Jazzband member first! ### On the Jazzband site Each project has a page on the Jazzband website that lists a number of important URLs on GitHub. One of those links is for project team discussions. 1. Go to the [project list](/projects). 2. Select a project you'd like to discuss. 3. Click on the link shown next to **"Team discussions"**. ### On GitHub 1. Go to the members team on [Jazzband's GitHub organization page][jazzband-github-org]. Note: You'll be greeted here with Jazzband-wide discussions. Keep going for project-specific discussions. [jazzband-github-org]: https://github.com/orgs/jazzband/teams/members 2. There, select the ["Teams" tab][jazzband-team-tab] [jazzband-team-tab]: https://github.com/orgs/jazzband/teams/members/teams 3. Choose one of the existing project teams from the list and you'll be directed to the team discussions. > **Happy discussions!** [jazzband-projects]: /projects [jazzband-guidelines]: /about/guidelines [jazzband-coc]: /about/conduct --- ## File: docs/news/2021/06/04/stats-5-years.md title: Stats after 5 years tags: django, oss, python published: 2021-06-04T13:10:48+02:00 author: Jannis Leidel author_link: https://twitter.com/jezdez summary: Stats from the last 5 years of Jazzband. The past few years at Jazzband went by so quick, so here's a quick overview: #### Members * **~1,350 unique members** over the years * **\> 900 members** currently #### Projects * **~ 55 current projects**, 10 projects have left again * **~ 20 projects** are currently being proposed #### Activity * 160 people pushed **~6,000 commits** * **22,000 stars** from 14,500 people! #### Issues * **3,000 new issues** from ~2,000 people * **17,000 issue comments** by 4,000 people * 600 people **closed 2,500 issues** #### Pull requests * **3,000 new pull requests** from ~ 1,000 people * **3,000 pull request comments** from 300 people * **3,500 closed pull requests** by 270 people Thank you all for your work! Feel free to [contact Jazzband](//about/contact) if you're interested in learning how these numbers were calculated. --- ## File: docs/news/2015/12/17/launching-jazzband.md title: Launching Jazzband tags: django, oss, python published: 2015-12-17T10:27:00+01:00 author: Jannis Leidel author_link: https://twitter.com/jezdez summary: We are all part of this. Jazzband is a cooperative experiment to reduce the stress of maintaining Open Source software projects. ### We are all part of this. [Jazzband](https://jazzband.co/) is a cooperative experiment to reduce the stress of maintaining Open Source software projects. It aims at lowering the barrier of entrance for people willing to step up as maintainers and grants access to GitHub repositories hosted under the [Jazzband GitHub organization](https://github.com/jazzband) to everyone who joins. It’s supposed to simplify the process of managing a volunteer project for the original author(s) and makes stepping away easier. Its purpose can most easily be characterized as _“relief”_: - Relief from the _exhausting parts_ of being a maintainer — either of big or small software projects, widely used or only written for one task. - Relief of _not knowing_ how to get a fix landed or a feature added as a user. It normalizes the relationship between creators and consumers, between “core committers” and “end users”. There are a few [guidelines](/about/guidelines) to follow before deciding to transfer existing projects to the Jazzband or creating a new one like agreeing to the Jazzband’s [code of conduct](/about/conduct). Some optional [features](/about/releases) should also be considered to be used by the Jazzband [projects](/projects) to further improve the contribution workflow. I guess some band [members](/members) will want to take the lead singer role, but you know how it is not everyone is great at everything so let’s support them and enjoy the diversity – there is more to a band than its lead singer. Assume positive intent when playing together in the band, but don’t hesitate to call out naysayers. Fix conflicts and differences of ideas by discussion and finding compromises. In other words: _Play together._ My role will be the “roadie who also happens to play the guitar sometimes” – I’ll stay in the background and let the band members do their thing. See the Jazzband [roadies](/roadies) page for others that have that role. Sadly nothing of Jazzband will make financing Open Source software development easier – it's currently out of scope of Jazzband. And I guess the music industry is a bad analogy to figure that out anyway. But hey, at least you shouldn’t feel bad about moving on to your next “band” or “gig” only because you think you owe it to your “fans” to stick around. The Jazzband will have your back, just [join](https://jazzband.co/) and let's see where it brings us. Anyways, that’s all for now. Please feel free to learn more [about Jazzband](/about) and the see [FAQ](https://jazzband.co/about/faq) in case you have more questions. **We are all part of this.** --- ## File: docs/news/index.md layout: news_index Read up on the Jazzband news in the following articles. There is also an [Atom feed](/news/feed) available if needed. --- ## File: docs/about/conduct.md title: Code of Conduct navigation: Conduct As contributors and maintainers of the Jazzband projects, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in the Jazzband a harassment-free experience for everyone, regardless of the level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct The Jazzband roadies have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. By adopting this Code of Conduct, the roadies commit themselves to fairly and consistently applying these principles to every aspect of managing the jazzband projects. Roadies who do not follow or enforce the Code of Conduct may be permanently removed from the Jazzband roadies. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Roadies are obligated to maintain confidentiality with regard to the reporter of an incident. This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] [homepage]: https://contributor-covenant.org [version]: https://contributor-covenant.org/version/1/3/0/ --- ## File: docs/about/contact.md title: Contact ### Security !!! warn "No public issues!" Don't open GitHub issues or pull requests about security related questions publicly. Please refer to the [security section](/security) about how to report security issues. ### News See the [news section](/news) for some more detailed status reports and other news items from the roadies and members. Feel free to follow [Jazzband on Twitter](https://twitter.com/jazzbandco), too. ### Matrix Jazzband members and interested folk may want to join the discussion in the Matrix Space: `#jazzband:matrix.org`. This is especially convenient for people who don't want to figure out how to use [IRC](#irc) these days. [![Matrix Badge]][Matrix Space] [Matrix Badge]: https://img.shields.io/matrix/jazzband:matrix.org?label=Discuss%20on%20Matrix%20at%20%23jazzband%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=for-the-badge [Matrix Space]: https://matrix.to/#/%23jazzband:matrix.org ### IRC Jazzband members and interested folk may want to join the discussion in the IRC channel on Libera.Chat (`irc.libera.chat`): `#jazzband` Direct link to channel via [IRCCloud](https://www.irccloud.com/): [](https://www.irccloud.com/invite?channel=%23jazzband&hostname=irc.libera.chat&port=6697&ssl=1) Note that it is also possible to connect to this channel through a built-in [Matrix](#matrix) bridge, via `#jazzband:libera.chat`. ### Issues You can also reach the [roadies](/roadies) via [GitHub issues](https://github.com/jazzband/help/issues) or email at `roadies@jazzband.co`. !!! warn "Project specific issues" The Jazzband [roadies](/roadies) are not responsible for individual project issues. Please see the appropriate [project repository](/projects) for the issue management. --- ## File: docs/about/faq.md title: FAQ ### What's the purpose of the Jazzband? The purpose of the Jazzband is to help Open Source projects on GitHub share responsibility for software maintenance. It's essentially a GitHub organization that is open to everyone who is willing and able to maintain its projects. It was born out of necessity of expanding the group of maintainers of some projects whose original authors weren't able to effectively manage them when people volunteered to help out. In that sense, it's hoped that opening the contribution process will lower the barrier of entry for new contributors and reduce the stress that comes with receiving commit access to a project by spreading it to a bigger group. **"We are all part of this"** means that we share the responsibilities of open source software development, including dreaming big, acting positively and failing sometimes. It'll be okay since we're not alone. ### How do I report a security incident? See the [security policy page](/about/security). ### How do I join the Jazzband? First [login with GitHub](/account/login) and then follow the instructions on your [account dashboard](/account). ### How do I transfer a project to Jazzband? Full instructions for transferring a repository can be found on the [guidelines page](/about/guidelines). You should transfer your project to the Jazzband organization on GitHub, and then the Jazzband bot will open an issue with the outstanding tasks to complete the transfer. ### Does the Jazzband have a code of conduct? Yes, the Jazzband follows a [Contributor Code of Conduct](/about/conduct) that was adopted from the [Contributor Covenant](https://contributor-covenant.org). Please refer to the conduct page for more information for how to report a breach of conduct. ### How do I report abuse or other incidents? Write an email to `roadies@jazzband.co` – especially if it's a breach of conduct following our [code of conduct](/about/conduct). ### Are you processing or storing any personal data on the Jazzband website? When logging into the Jazzband site you consent to fetching your profile data, email address(es) and the team and organization membership status of your [GitHub] account. That data is used to determine whether you're already a member, invite you to the Jazzband GitHub organization if required, check if you have a verified email address, show you in the members list and other necessary uses. The site uses cookies that are required for this site to work correctly (e.g. session cookies) but doesn't include any 3rd party cookies. [GitHub]: https://github.com/ ### Can I withdraw my consent to processing or storing any data about me? Of course, it's your data! Please get in touch with the [roadies](/roadies) to do that. ### How do I leave the Jazzband again? Simply head to your [account dashboard](/account), click on "leave" (or directly [here](/account/leave)) and confirm that you want to leave by entering your GitHub username. You can re-join anytime, simply [login](/account/login) and then click on the "Send invitation" link on your [account dashboard](/account). !!! note "Data retention" We retain some information about your previous membership to simplify the ability to join again. If you want to delete all Jazzband data about you that was fetched from the GitHub API, please let the [roadies](/roadies) know. **Alternatively**, you can remove yourself from the Jazzband GitHub organization on your [personal settings](https://github.com/settings/organizations) over at GitHub. There you can see the GitHub organizations you're a member of and easily leave the Jazzband by clicking on the "Leave" button next to it. See the note about data retention above, too. ### How can I edit my profile data (e.g. name)? The profile data we store is regularly fetched from the GitHub profile API and kept up-to-date with it. If you'd like to change any data please update it over at GitHub to be changed on the Jazzband site as well. ### How can I export all data that is stored about me? In case you'd like to export all data that is stored about you, please contact the [roadies](/roadies) or create a [public GitHub issue](/roadies/issue) and we'll send it to you. ### How do releases to the Python Package Index work? Please refer to the separate [releases](/about/releases) page. ### What's in it for the roadies? Nothing, if you mean monetary compensation. The roadies are volunteers just like other contributors and members. ### How do I disable email notifications for Jazzband repositories? You may want to modify your notification settings on GitHub in your [personal settings](https://github.com/settings/notifications). Especially GitHub's feature **"Automatic watching"** can create lots of notification traffic in big GitHub organizations. Feel free to disable it and watch individual projects manually instead. Alternatively you can also [ignore repositories] and continue to receive notifications for the rest of your [watched repositories]. [ignore repositories]: https://help.github.com/articles/unwatching-repositories/ [watched repositories]: https://github.com/watching ### Why am I not listed as an organization member on GitHub? By default GitHub will set your Jazzband organization membership as private and you have to change it to public if you'd like to be publicly shown as member of the organization on [github.com/jazzband](https://github.com/jazzband). You can fix it like this: - Login into GitHub - Head over to the [organization's people site](https://github.com/orgs/jazzband/people) - Search for your nickname in the "Find a member..." field - Change the "Organization visibility" setting from "Private" to "Public" --- ## File: docs/about/guidelines.md title: Guidelines When creating a new project or moving an existing one to the Jazzband there are some guidelines to follow. They exist to make sure that the Jazzband stays useful as a place to share responsibility for software maintenance when a number of projects are created at or moved to it. To initiate the transfer to Jazzband, you should use [Github's Transfer Feature](https://help.github.com/en/github/administering-a-repository/transferring-a-repository) to transfer the repository to the Jazzband organization. The Jazzband bot will then open an issue in the [Roadies help repo](https://github.com/jazzband/help/issues/38) with a TODO list that you can work through to complete the transfer, which is mainly to ensure the below guidelines are being followed. Please do read the guidelines in full before initiating a transfer. !!! warn "Please consider these guidelines carefully before deciding to transfer a repository to the Jazzband GitHub organization." The Jazzband [roadies](/roadies) will enforce the guidelines and won't hesitate to remove projects from the GitHub organization if required. The section about [frequently asked questions](/about/faq) may be interesting to you as well. ### Viability There is no place in the Jazzband for proofs of concept or projects that exist as one-off toys. The Jazzband expects projects to cover non-trivial functionality and is not a code snippet hoster. Established projects with a history of outside contributions that seek more maintainers are best suited for transfer to the Jazzband. Projects should have an orderly hand-over to Jazzband with agreement from the previous maintainer(s). For example, forking a project to transfer it to Jazzband is frowned upon. ### Documentation Projects require prose documentation for end users **and** contributors. Inline code documentation is considered an indicator for a high quality of code and is also strongly recommended. Document as much as possible and don't rely on autodoc alone. Write like you're addressing yourself in a few years. ### Tests Projects must have tests that are easy to run. Automatic testing based on contributions (e.g. GitHub Actions) is also strongly encouraged. The test coverage requirement follows the "perfect is the enemy of the good" motto -- it's enough if the tests cover the core API of the project. Test as much as needed to make maintenance a breeze. Don't be dogmatic. ### Conduct Projects are required to adopt and follow the Jazzband code of conduct. Please see the [Contributor Code of Conduct](/about/conduct) for more information what that entails and how to report conduct violations. Adhering to the contributor code of conduct is key in keeping the Jazzband together. ### Contributing Guidelines Projects have to add a `CONTRIBUTING.md` or `CONTRIBUTING.rst` file to their repository so it's automatically displayed when new issues and pull requests are created. A `CONTRIBUTING.md` ([Markdown]) file needs to contain this header: ```md [](https://jazzband.co/) This is a [Jazzband](https://jazzband.co/) project. By contributing you agree to abide by the [Contributor Code of Conduct](https://jazzband.co/about/conduct) and follow the [guidelines](https://jazzband.co/about/guidelines). ``` A `CONTRIBUTING.rst` ([reStructuredText]) file needs to contain this header: ```rst .. image:: https://jazzband.co/static/img/jazzband.svg :target: https://jazzband.co/ :alt: Jazzband This is a `Jazzband `_ project. By contributing you agree to abide by the `Contributor Code of Conduct `_ and follow the `guidelines `_. ``` See the default [contributing guideline] file for how it'd look like. Feel free to add a similar paragraph to your `README` file. Of course extending the contributing document with your project's contributing guide is highly encouraged, too. See GitHub's documentation on [contributing guidelines] for more information. [contributing guidelines]: https://help.github.com/articles/setting-guidelines-for-repository-contributors/ [contributing guideline]: https://github.com/jazzband/.github/blob/main/CONTRIBUTING.md [reStructuredText]: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html [Markdown]: https://daringfireball.net/projects/markdown/syntax ### Badges You may also want to use Jazzband badges (following the [shields.io] spec) using the following URL: `https://jazzband.co/static/img/badge.svg`. It looks like this: Markdown: ```md [](https://jazzband.co/) ``` reStructuredText: ```rst .. image:: https://jazzband.co/static/img/badge.svg :target: https://jazzband.co/ :alt: Jazzband ```