Library / SDK
brainix/pottery avatar
brainix/pottery

Pottery: Redis containers that behave like Python dicts and sets

Redis for humans. 🌎🌍🌏

1,245 stars71 forksPythonApache-2.0

At a glance

What is it?
Pottery wraps a Redis connection in Python container types, so RedisDict, RedisSet, RedisList, RedisCounter and RedisDeque behave like the builtins they imitate, and it adds the resilience pieces a service actually needs, distributed locks, caches and bloom filters. The catch is that every one of these objects is remote, so the semantics of the builtin are only an approximation.
Who is it for?
Pottery suits a Python service that wants shared state across processes with the ergonomics of the standard containers, and that needs distributed locking or a Redis cache without hand writing the command sequences. It does not suit code that assumes a local dict is free, because every operation here is a network round trip, and it does not suit data that is not JSON serializable.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Containers that forward to Redis instead of holding memory

Pottery is a Python library that presents Redis as a set of familiar container types. The pitch in the package description is that Redis is good but its commands are not always intuitive, and if you know how to use Python dicts you already know how to use Pottery. The mechanics are consistent across the whole library. You construct a Redis client once, then pass it and a key name to a container, and the container talks to the server on every operation.

python
>>> from redis import Redis
>>> redis = Redis.from_url('redis://localhost:6379/1')
python
>>> from pottery import RedisDict
>>> tel = RedisDict({'jack': 4098, 'sape': 4139}, redis=redis, key='tel')
>>> tel['guido'] = 4127
>>> tel['jack']
4098

The first two keyword arguments are always the client and the key name, and after that the object is used like the builtin it imitates. That includes the parts people actually rely on: iteration order, sorted, membership tests, deletion, slicing on the list type, set algebra with the difference, union, intersection and symmetric difference operators, and Counter methods like most_common, elements and subtract. The important mental shift is that the container is a handle onto a key in Redis rather than an object in your process, so two workers holding the same key name see the same data, and nothing is held in memory between calls. The library is Apache-2.0 licensed, the primary language is Python, and it is installed from PyPI with a single command.

Installing Pottery and the client version it expects

Installation is a pip install, and the package pulls in the Redis client as a dependency.

shell
$ pip3 install pottery

The pinned dependency list in the repository is worth a look before you pin the library itself, because it tells you which client generation the code was written against. The requirements file names redis 8.1.0 alongside ast_serialize, hiredis and mmh3, the latter being the murmur3 hash helper that the bloom filter support relies on. The dev requirements add pytest, pytest-asyncio and pytest-cov for the test suite, mypy and flake8 for typing and linting, bandit for the security checks, and isort for import ordering. The package is set up with setup.py and the version string in that file is 3.0.1, matching the latest published release. The Makefile shows the maintainer's own workflow, where make install builds a local Python environment, and it also expects redis itself among the formulae it wants present, since the tests need a live server rather than a mock. Practically, the choice you have to make is whether to take the pinned client version or let pip resolve the newest one, and for a library that reaches into Redis internals like this one, matching the pinned version is the safer default.

RedisList is really a deque, and the documentation says so

The most useful thing in the documentation is the limitations list attached to each container, because that is where the illusion of the builtin breaks. RedisDict, RedisSet and RedisList all require their contents to be JSON serializable, which rules out storing arbitrary Python objects without a custom encoder. The RedisList entry goes further and explains the data structure mismatch. Python implements list with an array, so index access is constant time, while Redis implements its list type as a doubly linked list. Inserting at the head or tail of a RedisList is therefore fast, O(1), but accessing elements by index is slow, O(n). The documentation reaches the obvious conclusion and tells you that in terms of performance and ideal use cases RedisList is closer to Python's deque than to Python's list, and that you should consider RedisDeque instead. That is a good example of the library being honest about where the abstraction leaks. A RedisSet adds one method that has no builtin equivalent, contains_many(), which tests membership for several elements in one round trip instead of one call per element, which is a meaningful saving when you are checking a batch of candidates against a set.

Redlock and AIORedlock for service coordination

Beyond the containers, Pottery includes the resilience pieces a microservice needs, starting with distributed locks. Redlock is the synchronous implementation, with a synchronize() method described as the entry point, and AIORedlock is the asyncio counterpart, which is consistent with the repository topics that include asyncio and the pytest-asyncio dependency in the dev requirements. The point of providing these is the one the project states about itself: it is useful for implementing microservice resilience patterns. A lock obtained through Redlock gives you mutual exclusion across processes that do not share memory, which is exactly the case a local threading.Lock cannot cover. The trade-off is inherent to the design rather than to the implementation. Because the lock lives in Redis, its validity depends on that Redis instance being reachable, and the lock acquisition is a network operation, so a slow server turns into slow code paths. The library also provides NextID for monotonic identifier generation, which serves the same coordination problem from the other direction when you need a unique id that is safe to hand out across workers.

redis_cache, CachedOrderedDict and ContextTimer for the request path

Three utilities target the hot path of a web service. redis_cache() is a decorator that caches a function's return value in Redis, so a repeated call with the same arguments reads from the cache rather than recomputing. CachedOrderedDict is the container version of the same idea, an ordered dictionary whose contents are backed by Redis, which suits code that was written against an OrderedDict and needs the data to outlive the process. ContextTimer is a context manager for measuring how long a block of code takes, which in a service that already depends on Redis is a natural place to keep timing because the measurement travels with the request context rather than with a local variable. Taken together these three are the part of Pottery that goes beyond a nicer API for the same commands. They are the reason the description claims the library is useful for microservice resilience patterns rather than only for convenience. The practical caveat is that caching a function whose result depends on external state you did not include in the cache key is a bug in your code that the library cannot detect, and the same applies to a ContextTimer that measures a block including network time, which is a number worth understanding before it goes on a dashboard.

Bloom filters and HyperLogLogs for approximate answers

The last group covers probabilistic data structures, and these are the two you are least likely to build yourself. A Bloom filter answers a membership question with a tunable false positive rate and a fixed memory footprint, and the HyperLogLog structure estimates the cardinality of a set with a bounded and very small amount of memory. In the Pottery API they are Redis backed, so the data is shared across processes the same way the containers are, and the requirements file shows the supporting libraries, with mmh3 supplying the murmur3 hash the bloom filter needs. The difference in approach from a plain Redis set is the whole point. A set of every identifier you have seen grows without limit and stores the identifiers themselves, while a bloom filter answers a yes or no question about a key you probably will never add, and a HyperLogLog answers how many distinct things you have seen without storing any of them. Neither is exact, and neither is meant to be. The bloom filter can tell you a key is definitely absent, and the HyperLogLog estimate has an error bar. If your use case needs certainty, for example deciding whether to write a record, these structures are the wrong tool and a set is the right one.

Where Pottery is the wrong tool

The main objection is that the convenience has a cost the builtin does not. Every read, write and membership test is a network round trip, so a RedisDict used in a hot loop is orders of magnitude slower than a dict, and code written as if the container were local will be slow in a way that is not obvious from reading the Python. The JSON serializable requirement is the second constraint, and it is a real one for a library that otherwise looks like it accepts anything a dict accepts. The list structure mismatch is the third, and the documentation resolves it by pointing you at RedisDeque, but only if you read the limitations rather than the example code. A fourth point is about scope: Pottery gives you containers, locks, caches and probabilistic structures, and nothing else. It is not a job queue, not a pub/sub layer, not a stream processor, and it does not add scripting or transactions on top of the client, so a design that needs those belongs with the client directly. A fifth consideration is release cadence. The most recent published release is v3.0.1 from 2025-03-21, and the previous two are v3.0.0 and v2.3.7 from February 2022, so the public version history is slow, while the last push to master was on 2026-10-17. That combination suggests active work on master that has not yet produced a tagged release, and it is the reason to read the diff between v3.0.1 and master before you depend on it.

Editorial conclusion

Pottery suits a Python service that wants shared state across processes with the ergonomics of the standard containers, and that needs distributed locking or a Redis cache without hand writing the command sequences. It does not suit code that assumes a local dict is free, because every operation here is a network round trip, and it does not suit data that is not JSON serializable. Before you adopt it, read the limitation notes on RedisList, where index access is O(n) against Redis' linked list, check that the installed redis client version matches the one in requirements.txt, and pin the 3.0.1 release deliberately, since the last push was on 2026-10-17 while the most recent published version is v3.0.1 from 2025-03-21.

Frequently asked questions

How do I install Pottery and connect it to Redis?

Install it with pip3 install pottery, then create a client with Redis.from_url('redis://localhost:6379/1') and pass that client and a key name to any container, for example RedisDict({'jack': 4098}, redis=redis, key='tel').

What are the limitations of Pottery's Redis containers?

Keys, values and elements must be JSON serializable, and RedisList behaves more like a deque than a list because index access on Redis' linked list is O(n), so the documentation suggests RedisDeque instead for that use case.

Does Pottery provide distributed locking?

Yes. Redlock offers a synchronous synchronize() method and AIORedlock is the asyncio version, both built on top of Redis so the lock is shared across processes.

What licence is Pottery released under and what is the latest version?

The repository declares the Apache License, Version 2.0, and the version in setup.py is 3.0.1, matching the latest published release v3.0.1 from 2025-03-21.

Official sources

  1. brainix/pottery on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/brainix-pottery.svg)](https://hysenlabs.com/projects/brainix-pottery)

Was this useful?