### Install Pottery and Setup Redis Source: https://github.com/brainix/pottery/blob/master/_autodocs/API-INDEX.md Install the Pottery library using pip. Set up a local Redis server or use Docker for a containerized environment. ```bash # Install pip install pottery # Setup Redis redis-server # Or with Docker docker run -p 6379:6379 redis:latest ``` -------------------------------- ### Development Redis Setup with Pottery Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md A simplified setup for development using a local Redis instance and auto-generated keys for Pottery containers. Ideal for quick local testing and development cycles. ```python from redis import Redis from pottery import RedisDict # Development: local Redis, auto-generated keys redis = Redis() # localhost:6379/0 data = RedisDict(redis=redis) # Random key ``` -------------------------------- ### Install Pottery Source: https://github.com/brainix/pottery/blob/master/README.md Install the Pottery library using pip. ```shell pip3 install pottery ``` -------------------------------- ### Redis Cache Usage Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/types.md Demonstrates how to use the redis_cache decorator and access cache information. ```Python @redis_cache(redis=redis, key='cache') def expensive(n): return n * 2 expensive(5) info = expensive.cache_info() print(f'Hits: {info.hits}, Misses: {info.misses}') print(f'Cache size: {info.currsize}') ``` -------------------------------- ### Start ContextTimer Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Starts the timer. Raises a RuntimeError if the timer has already been started or stopped. ```python timer = ContextTimer() timer.start() ``` -------------------------------- ### Error Handling Examples Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Illustrates potential RuntimeError exceptions when calling elapsed(), start(), or stop() in invalid states (e.g., before starting, starting twice, stopping twice). ```python from pottery import ContextTimer timer = ContextTimer() # Not started yet try: timer.elapsed() # RuntimeError except RuntimeError as e: print(f'Error: {e}') # Start timer timer.start() # Try to start again try: timer.start() # RuntimeError except RuntimeError as e: print(f'Error: {e}') # Stop timer timer.stop() # Try to stop again try: timer.stop() # RuntimeError except RuntimeError as e: print(f'Error: {e}') # Can still read elapsed time after stop print(timer.elapsed()) ``` -------------------------------- ### Advanced Example: Fibonacci with redis_cache Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-cache.md This example demonstrates caching a recursive Fibonacci function to improve performance. It also shows how to check cache efficiency, invalidate specific cache entries using `__bypass__`, and clear the entire cache. ```python from pottery import redis_cache import time redis = Redis() @redis_cache(redis=redis, key='fibonacci-cache', timeout=3600) def fibonacci(n): if n < 2: return n # Note: This is inefficient; using cache to speed up time.sleep(0.1) return n # Generate cached values for i in range(10): result = fibonacci(i) # Check cache effectiveness info = fibonacci.cache_info() print(f'Efficiency: {info.hits / (info.hits + info.misses):.1%}') # Invalidate cache for specific args fibonacci.__bypass__(5) # Recompute and cache 5 # Clear all cached values fibonacci.cache_clear() ``` -------------------------------- ### Complete Redis Setup with Pottery Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Demonstrates initializing RedisDict, Redlock, and NextID with explicit Redis clients and a cluster configuration. Useful for production environments requiring robust Redis connections. ```python import os from redis import Redis from pottery import RedisDict, Redlock, NextID # Configure Redis connection os.environ['REDIS_URL'] = 'redis://localhost:6379/0' # Or create explicit client redis = Redis.from_url('redis://localhost:6379/0', socket_timeout=1) # Set up cluster (5 masters for production) masters = { Redis.from_url('redis://master1:6379/0'), Redis.from_url('redis://master2:6379/0'), Redis.from_url('redis://master3:6379/0'), Redis.from_url('redis://master4:6379/0'), Redis.from_url('redis://master5:6379/0'), } # Initialize containers and primitives data = RedisDict(redis=redis, key='app-data') lock = Redlock(key='critical-section', masters=masters, auto_release_time=5.0) ids = NextID(key='user-ids', masters=masters) ``` -------------------------------- ### Initialize and Use RedisDict Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-dict.md Demonstrates creating a RedisDict with initial data, adding, retrieving, checking membership, deleting items, and getting the length. Requires a Redis client instance. ```python from redis import Redis from pottery import RedisDict redis = Redis.from_url('redis://localhost:6379/0') # Create with initial data tel = RedisDict({'jack': 4098, 'sape': 4139}, redis=redis, key='tel') # Add items tel['guido'] = 4127 # Retrieve items print(tel['jack']) # 4098 # Check membership if 'guido' in tel: print('Found guido') # Delete items del tel['sape'] # Get length print(len(tel)) # 2 ``` -------------------------------- ### CachedOrderedDict Initialization and Usage Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-cache.md Demonstrates initializing CachedOrderedDict, hydrating data, and checking cache misses. Use this to manage ordered data with Redis persistence. ```python from pottery import CachedOrderedDict from redis import Redis redis = Redis() # Search returns IDs [1, 2, 3, 4, 5] search_results = CachedOrderedDict( redis_client=redis, redis_key='search-results', dict_keys=(1, 2, 3, 4, 5), ) # Initially, all are cache misses print(sorted(search_results.misses())) # [1, 2, 3, 4, 5] # Hydrate from database search_results[1] = 'Document One' search_results[2] = 'Document Two' search_results[3] = 'Document Three' search_results[4] = 'Document Four' search_results[5] = 'Document Five' # Now, all cached print(sorted(search_results.misses())) # [] # Second search with some overlap search_results_2 = CachedOrderedDict( redis_client=redis, redis_key='search-results', # Same key = same cache dict_keys=(2, 4, 6, 8, 10), ) # Only 6, 8, 10 need hydration print(sorted(search_results_2.misses())) # [6, 8, 10] # Retrieve cached values print(search_results_2[2]) # 'Document Two' (from cache) print(search_results_2[4]) # 'Document Four' (from cache) # Hydrate misses search_results_2[6] = 'Document Six' search_results_2[8] = 'Document Eight' search_results_2[10] = 'Document Ten' # Iterate in order for key, value in search_results_2.items(): print(f'{key}: {value}') ``` -------------------------------- ### NextID Constructor Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Instantiate a NextID generator with a key, Redis masters, and configuration for error raising and number of tries. ```python from pottery import NextID id_gen = NextID( key='sequence-name', masters={redis1, redis2, redis3}, raise_on_redis_errors=False, num_tries=3 ) ``` -------------------------------- ### Default Redis Connection Setup Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Sets up a default Redis client instance using the REDIS_URL environment variable or a fallback to localhost. This is used when no explicit Redis client is provided. ```python import os from redis import Redis _default_url = os.environ.get('REDIS_URL', 'redis://localhost:6379/0') _default_redis = Redis.from_url(_default_url, socket_timeout=1) ``` -------------------------------- ### Initialize and Use RedisSet Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-set.md Demonstrates creating a RedisSet from an iterable, checking membership, adding, discarding elements, and getting the set's cardinality. Requires a Redis client instance. ```python from redis import Redis from pottery import RedisSet redis = Redis.from_url('redis://localhost:6379/0') # Create from iterable basket = RedisSet({'apple', 'orange', 'pear'}, redis=redis, key='basket') # Check membership if 'orange' in basket: print('Found orange') # Add element basket.add('banana') # Remove element basket.discard('apple') # Get cardinality print(len(basket)) # 3 ``` -------------------------------- ### Redlock Constructor Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Instantiate a Redlock with specified key, Redis masters, and configuration for auto-release time, context manager behavior, and error raising. ```python from pottery import Redlock lock = Redlock( key='resource-name', masters={redis1, redis2, redis3, redis4, redis5}, auto_release_time=10.0, context_manager_blocking=False, context_manager_timeout=-1, raise_on_redis_errors=False ) ``` -------------------------------- ### REDIS_URL Environment Variable Examples Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Demonstrates various formats for the REDIS_URL environment variable, including basic, authenticated, TLS, and Unix socket connections. ```bash # Examples export REDIS_URL='redis://localhost:6379/0' export REDIS_URL='redis://username:password@localhost:6379/0' export REDIS_URL='rediss://secure.redis.server:6380/0' # TLS export REDIS_URL='unix:///tmp/redis.sock?db=0' # Unix socket ``` -------------------------------- ### Example Usage of JSONTypes with RedisDict Source: https://github.com/brainix/pottery/blob/master/_autodocs/types.md Demonstrates assigning various JSONTypes values to a RedisDict instance. Ensure Redis connection is established. ```python from pottery import RedisDict # Valid JSONTypes values my_dict = RedisDict(redis=redis, key='data') my_dict['null'] = None my_dict['bool'] = True my_dict['number'] = 42 my_dict['float'] = 3.14 my_dict['string'] = 'hello' my_dict['list'] = [1, 2, 3] my_dict['nested'] = {'a': 1, 'b': [2, 3]} ``` -------------------------------- ### Standalone Usage with Explicit Start/Stop Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Demonstrates using ContextTimer with explicit start() and stop() calls, showing how elapsed time is measured and remains constant after stopping. ```python import time from pottery import ContextTimer timer = ContextTimer() timer.start() time.sleep(0.1) print(timer.elapsed()) # ~100 time.sleep(0.05) timer.stop() print(timer.elapsed()) # ~150 time.sleep(0.1) print(timer.elapsed()) # ~150 (unchanged after stop) ``` -------------------------------- ### Initialize and Use RedisList Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-list.md Demonstrates how to create a RedisList from an iterable, access elements by index, slice the list, get its length, and iterate over its elements. Requires a Redis client instance. ```python from redis import Redis from pottery import RedisList redis = Redis.from_url('redis://localhost:6379/0') # Create from iterable squares = RedisList([1, 4, 9, 16, 25], redis=redis, key='squares') # Access elements print(squares[0]) # 1 print(squares[-1]) # 25 # Slice print(squares[-3:]) # [9, 16, 25] # Get length print(len(squares)) # 5 # Iterate for sq in squares: print(sq) ``` -------------------------------- ### Dictionary-like Operations Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-counter.md Shows how to use standard dictionary methods like membership testing, iteration over keys, accessing items, and getting the length of the RedisCounter. ```python # Check membership if 'red' in c: print('Found') # Iterate over keys for key in c: print(key) # Get all items for key, count in c.items(): print(f'{key}: {count}') # Get length print(len(c)) ``` -------------------------------- ### Context Manager Usage Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Use ContextTimer as a context manager for automatic start and stop. Elapsed time can be retrieved both during and after the 'with' block. ```python import time from pottery import ContextTimer with ContextTimer() as timer: time.sleep(0.1) elapsed_during = timer.elapsed() # ~100 # Timer automatically stopped on exit elapsed_after = timer.elapsed() # ~100 (same as during) ``` -------------------------------- ### Redlock Error Handling Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/redlock.md Demonstrates how to catch and handle specific exceptions that can occur during Redlock operations such as acquiring, releasing, and extending locks. ```python import contextlib from pottery import ( Redlock, QuorumNotAchieved, ReleaseUnlockedLock, TooManyExtensions, ) lock = Redlock(key='resource', masters={redis}) # Handle quorum failures try: if not lock.acquire(timeout=5.0): print('Could not acquire lock within timeout') except QuorumNotAchieved: print('Could not achieve quorum on masters') # Handle release errors try: lock.release() except ReleaseUnlockedLock: print('Lock was not held') # Handle extension errors try: lock.extend(10.0) except TooManyExtensions: print('Lock has been extended too many times') except ExtendUnlockedLock: print('Lock is not currently held') ``` -------------------------------- ### Hourly and Daily Aggregation Source: https://github.com/brainix/pottery/blob/master/_autodocs/hyperloglog.md Aggregate unique counts over different time granularities. This example shows creating separate HyperLogLogs for each hour and then merging them into a daily total. ```python # Track unique hourly visitors hour_visitors = {} for hour in range(24): hour_visitors[hour] = HyperLogLog( redis=redis, key=f'visitors:hour:{hour}' ) # Merge hourly HyperLogLogs for daily total daily_total = HyperLogLog(redis=redis, key='visitors:daily') for hour in range(24): daily_total.update(hour_visitors[hour]) print(f'Daily unique visitors: ~{len(daily_total)}') ``` -------------------------------- ### Illustrate Sequence Gaps Source: https://github.com/brainix/pottery/blob/master/_autodocs/nextid.md This example illustrates how concurrent ID generation by multiple clients can lead to gaps in the generated sequence. Use IDs as opaque identifiers. ```python # Client 1 generates: 1, 2 # Client 2 generates: 3 # Client 3 generates: 6, 7, 8 (gap from 3 to 6 possible) ``` -------------------------------- ### TooManyExtensions Exception Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Illustrates catching the TooManyExtensions exception, which is raised when a Redlock is extended more times than permitted. This prevents indefinite lock holding. ```python from pottery import Redlock, TooManyExtensions lock = Redlock(key='resource', masters={redis}) if lock.acquire(): try: # Extend lock repeatedly for i in range(100): lock.extend(1.0) except TooManyExtensions: print('Lock extended too many times') finally: lock.release() ``` -------------------------------- ### KeyExistsError Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Raised when attempting to initialize a container on a Redis key that already exists with initial data. Use a different key, clear the existing key, or initialize without data to recover. ```python from pottery import RedisDict, KeyExistsError from redis import Redis redis = Redis() # Create first dict dict1 = RedisDict({'a': 1}, redis=redis, key='mydata') # Try to create another on same key with data try: dict2 = RedisDict({'b': 2}, redis=redis, key='mydata') except KeyExistsError as e: print(f'Key {e.key} already exists in Redis {e.redis}') # This works (no initial data means we accept existing key) dict3 = RedisDict(redis=redis, key='mydata') ``` -------------------------------- ### ExtendUnlockedLock Exception Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Shows how to handle the ExtendUnlockedLock exception, which occurs when attempting to extend a Redlock that is not currently held. Ensure the lock is acquired before extending. ```python from pottery import Redlock, ExtendUnlockedLock lock = Redlock(key='resource', masters={redis}) try: lock.extend(5.0) # Lock not acquired yet except ExtendUnlockedLock: print('Cannot extend unlocked lock') # Correct usage if lock.acquire(): try: lock.extend(5.0) # OK finally: lock.release() ``` -------------------------------- ### Testing Redis Setup with Pottery Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Configures Redis for testing using pytest fixtures, ensuring string decoding and database flushing after each test. Useful for creating isolated and clean test environments. ```python import pytest from redis import Redis from pottery import RedisDict @pytest.fixture def redis(): r = Redis(decode_responses=True) # Strings instead of bytes yield r r.flushdb() # Clean up after test def test_dict(redis): d = RedisDict({'a': 1}, redis=redis, key='test') assert d['a'] == 1 ``` -------------------------------- ### Redlock Distributed Primitive Requirements Source: https://github.com/brainix/pottery/blob/master/_autodocs/README.md Illustrates the required setup for distributed primitives like Redlock, emphasizing the need for multiple Redis masters for high availability and consensus algorithms. A minimum of 3 masters is recommended, with 5 advised for production environments. ```python from pottery import Redlock # Required for consensus algorithms lock = Redlock( key='resource-name', masters={redis1, redis2, redis3, redis4, redis5} # Minimum 3, use 5 in production ) ``` -------------------------------- ### Bloom Filter with 1% False Positive Rate Source: https://github.com/brainix/pottery/blob/master/_autodocs/bloom-filter.md Instantiate a Bloom Filter with a specific `false_positives` value to control the acceptable probability of false positives. This example sets a 1% false positive rate. ```python # 1% false positive rate users = BloomFilter( num_elements=100, false_positives=0.01, # 1 in 100 tests returns True incorrectly redis=redis, key='users' ) ``` -------------------------------- ### ReleaseUnlockedLock Exception Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Demonstrates handling the ReleaseUnlockedLock exception, raised when trying to release a Redlock that is not held. This prevents errors when releasing a lock that was never acquired or already released. ```python from pottery import Redlock, ReleaseUnlockedLock import contextlib lock = Redlock(key='resource', masters={redis}) # Wrong: release without acquire try: lock.release() except ReleaseUnlockedLock: print('Lock not held') # Correct usage if lock.acquire(): lock.release() # Or suppress the error if uncertain with contextlib.suppress(ReleaseUnlockedLock): lock.release() ``` -------------------------------- ### ContextTimer as a Context Manager Source: https://github.com/brainix/pottery/blob/master/README.md Utilize ContextTimer as a context manager for automatic start and stop. Elapsed time is measured within the 'with' block and can be accessed after exiting. This is useful for timing specific code sections. ```python >>> tests = [] >>> with ContextTimer() as timer: ... time.sleep(0.1) ... tests.append(100 <= timer.elapsed() < 200) >>> time.sleep(0.1) >>> tests.append(100 <= timer.elapsed() < 200) >>> tests [True, True] >>> ``` -------------------------------- ### RandomKeyError Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Raised when Pottery cannot generate a unique random Redis key after multiple collision attempts. Provide an explicit key, clear old keys, or use a different Redis instance to recover. ```python from pottery import RedisDict, RandomKeyError from redis import Redis redis = Redis() # If Redis is heavily populated with pottery: keys try: # This auto-generates a key; may fail if all random attempts collide dict1 = RedisDict(redis=redis) except RandomKeyError as e: print(f'Could not generate unique key after {e.key}') ``` -------------------------------- ### Get Elapsed Time Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Retrieves the elapsed time in milliseconds since the timer started. If the timer is running, it returns the time elapsed so far. If stopped, it returns the total time between start and stop. Raises a RuntimeError if the timer was never started. ```python import time from pottery import ContextTimer timer = ContextTimer() timer.start() time.sleep(0.1) elapsed_ms = timer.elapsed() # ~100 ``` -------------------------------- ### QueueEmptyError Example (Conceptual) Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Raised when a non-blocking get operation is called on an empty Redis-backed queue. This exception inherits from `queue.Empty` for standard library compatibility. ```python # Example if RedisQueue existed: # try: # item = queue.get_nowait() # except QueueEmptyError: # print('Queue is empty') ``` -------------------------------- ### Monitor Unique Stream Values Source: https://github.com/brainix/pottery/blob/master/_autodocs/hyperloglog.md Use HyperLogLog to monitor for unique values within a data stream. This example shows how to add values and trigger an alert if the number of unique items exceeds a specified threshold. ```python # Monitor unique values in a data data_stream unique_values = HyperLogLog(redis=redis, key='stream-unique') while True: value = data_stream.get() unique_values.add(value) if len(unique_values) > 100_000: alert('Stream diversity exceeded threshold') ``` -------------------------------- ### Initialize Redis Client Source: https://github.com/brainix/pottery/blob/master/README.md Set up a Redis client connection for use with Pottery containers. ```python from redis import Redis redis = Redis.from_url('redis://localhost:6379/1') ``` -------------------------------- ### Initialize and Use RedisDeque Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-deque.md Demonstrates creating a RedisDeque, adding and removing elements from both ends, and initializing a bounded deque with a maximum length. ```python from redis import Redis from pottery import RedisDeque redis = Redis.from_url('redis://localhost:6379/0') # Create deque d = RedisDeque('ghi', redis=redis, key='letters') # Add to right (most common) d.append('j') # Add to left d.appendleft('f') # Remove from right d.pop() # Remove from left d.popleft() # Create with max length bounded = RedisDeque([1, 2, 3], maxlen=5, redis=redis, key='bounded') bounded.append(4) # OK bounded.append(5) # OK, now at maxlen bounded.append(6) # Removes leftmost element (1), adds 6 ``` -------------------------------- ### Initialize RedisCounter in various ways Source: https://github.com/brainix/pottery/blob/master/README.md Shows different methods to initialize a RedisCounter, including from an empty state, from an iterable, from keyword arguments, and from a dictionary. Use the 'redis' client and 'key' arguments for initialization. ```python >>> from pottery import RedisCounter >>> c = RedisCounter(redis=redis, key='my-counter') >>> c = RedisCounter('gallahad', redis=redis, key='my-counter') >>> c.clear() >>> c = RedisCounter({'red': 4, 'blue': 2}, redis=redis, key='my-counter') >>> c.clear() >>> c = RedisCounter(redis=redis, key='my-counter', cats=4, dogs=8) >>> c.clear() >>> c = RedisCounter(['eggs', 'ham'], redis=redis, key='my-counter') >>> c['bacon'] 0 >>> c['sausage'] = 0 >>> del c['sausage'] >>> c.clear() >>> c = RedisCounter(redis=redis, key='my-counter', a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b'] >>> c.clear() >>> RedisCounter('abracadabra', redis=redis, key='my-counter').most_common(3) [('a', 5), ('b', 2), ('r', 2)] >>> c.clear() >>> c = RedisCounter(redis=redis, key='my-counter', a=4, b=2, c=0, d=-2) >>> from collections import Counter >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c RedisCounter{'a': 3, 'b': 0, 'c': -3, 'd': -6} >>> ``` -------------------------------- ### Stop ContextTimer Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Stops the timer. Raises a RuntimeError if the timer was not started or already stopped. ```python timer.stop() ``` -------------------------------- ### Get Redlock Auto-Release Time Source: https://github.com/brainix/pottery/blob/master/_autodocs/redlock.md Retrieve the configured auto-release time for the Redlock instance. ```python timeout = printer_lock.auto_release_time ``` -------------------------------- ### Initialize and Use RedisList Source: https://github.com/brainix/pottery/blob/master/README.md Demonstrates initializing a RedisList with existing data and accessing elements by index and slice. Elements must be JSON serializable. ```python >>> from pottery import RedisList >>> squares = RedisList([1, 4, 9, 16, 25], redis=redis, key='squares') >>> squares RedisList[1, 4, 9, 16, 25] >>> squares[0] 1 >>> squares[-1] 25 >>> squares[-3:] [9, 16, 25] >>> squares[:] [1, 4, 9, 16, 25] >>> squares + [36, 49, 64, 81, 100] RedisList[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] >>> ``` -------------------------------- ### Get List Length Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-list.md Retrieve the total number of elements in the list. This operation has O(1) complexity. ```python print(len(squares)) ``` -------------------------------- ### Get RedisSet Cardinality Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-set.md Retrieves the number of elements currently in the RedisSet. This operation has O(1) complexity. ```python print(len(basket)) ``` -------------------------------- ### Initialize HyperLogLog Source: https://github.com/brainix/pottery/blob/master/_autodocs/hyperloglog.md Create a HyperLogLog instance to track unique elements. Specify the Redis client and a unique key for storage. If no key is provided, one will be auto-generated. ```python from redis import Redis from pottery import HyperLogLog redis = Redis() # Create HyperLogLog to track unique searches searches = HyperLogLog(redis=redis, key='daily-searches') ``` -------------------------------- ### Get Length (RedisDict) Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-dict.md Returns the number of key-value pairs in the RedisDict. This operation has O(1) complexity. ```python print(len(tel)) ``` -------------------------------- ### RedisSet Constructor Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-set.md Initializes a RedisSet with optional initial elements, a Redis client instance, and a specific Redis key. If no key is provided, it will be auto-generated. Raises KeyExistsError if the Redis key already exists. ```APIDOC ## __init__ ### Description Initialize a RedisSet. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method None ### Endpoint None ### Parameters - **iterable** (Iterable[JSONTypes]) - Optional - Initial elements - **redis** (Redis | None) - Optional - Redis client instance. Defaults to None (uses default Redis client). - **key** (str) - Optional - Redis key name. Defaults to '' (auto-generated). ### Raises - `KeyExistsError`: If the Redis key already exists. ### Example ```python from redis import Redis from pottery import RedisSet redis = Redis.from_url('redis://localhost:6379/0') # Create from iterable basket = RedisSet({'apple', 'orange', 'pear'}, redis=redis, key='basket') ``` ``` -------------------------------- ### Initialize ContextTimer Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Initialize a ContextTimer instance. No parameters are needed. ```python from pottery import ContextTimer timer = ContextTimer() ``` -------------------------------- ### Get Count for a Key Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-counter.md Retrieves the count for a specific key. Returns 0 if the key does not exist. O(1) complexity. ```python def __getitem__(self, key: JSONTypes) -> int ``` ```python c = RedisCounter(redis=redis, key='my-counter') print(c['red']) # 0 if not present ``` -------------------------------- ### Initialize RedisCounter Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-counter.md Demonstrates various ways to initialize a RedisCounter. Ensure a Redis client instance is provided or a default is available. The 'key' parameter specifies the Redis key name. ```python from redis import Redis from pottery import RedisCounter redis = Redis.from_url('redis://localhost:6379/0') # From iterable (counts occurrences) c1 = RedisCounter('gallahad', redis=redis, key='my-counter') # c1 = {'g': 1, 'a': 3, 'l': 1, 'h': 1, 'd': 1} # From dict c2 = RedisCounter({'red': 4, 'blue': 2}, redis=redis, key='colors') # From keyword arguments c3 = RedisCounter(redis=redis, key='items', cats=4, dogs=8) # Empty counter c4 = RedisCounter(redis=redis, key='empty') ``` -------------------------------- ### Get HyperLogLog cardinality Source: https://github.com/brainix/pottery/blob/master/README.md Retrieve the approximate number of distinct elements in the HyperLogLog using the `len()` function. Note that this is a probabilistic count. ```python >>> len(google_searches) 1 >>> ``` -------------------------------- ### Basic RedisSet Usage Source: https://github.com/brainix/pottery/blob/master/README.md Demonstrates creating and manipulating a RedisSet, a set-like container backed by Redis. Elements must be JSON serializable. ```python from pottery import RedisSet basket = RedisSet({'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}, redis=redis, key='basket') sorted(basket) 'orange' in basket 'crabgrass' in basket ``` -------------------------------- ### Get Cache Misses Keys Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-cache.md Retrieves an iterable of keys that have not yet been cached. Use this to identify which items need to be fetched and stored. ```python for key in search_results.misses(): search_results[key] = fetch_document(key) ``` -------------------------------- ### Using Default Redis Connection for Pottery Container Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Demonstrates instantiating a Pottery container without providing a Redis client, which will cause it to use the default client configured via REDIS_URL. ```python # Uses default from REDIS_URL d = RedisDict(key='mydata') ``` -------------------------------- ### Get the approximate size of a Bloom Filter Source: https://github.com/brainix/pottery/blob/master/README.md Retrieve an approximate count of elements added to the Bloom filter. Note that this value is a probabilistic approximation. ```python len(dilberts) ``` -------------------------------- ### Instantiating Redlock Source: https://github.com/brainix/pottery/blob/master/README.md Shows how to instantiate a Redlock, a distributed lock for coordinating access across machines. Specify the resource key and a set of Redis masters. ```python >>> from pottery import Redlock >>> printer_lock = Redlock(key='printer', masters={redis}, auto_release_time=.2) >>> ``` -------------------------------- ### Get Value by Key (RedisDict) Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-dict.md Retrieves a value from the RedisDict using its key. This operation has O(1) complexity. Raises KeyError if the key does not exist. ```python value = tel['jack'] ``` -------------------------------- ### HyperLogLog Constructor Source: https://github.com/brainix/pottery/blob/master/_autodocs/hyperloglog.md Initializes a HyperLogLog instance. You can provide an iterable of initial elements, a Redis client instance, and a custom Redis key name. ```APIDOC ## __init__ HyperLogLog ### Description Initialize a HyperLogLog. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method None ### Endpoint None ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | iterable | Iterable[RedisValues] | No | frozenset() | Initial elements to add | | redis | Redis | No | None (uses default) | Redis client instance | | key | str | No | '' (auto-generated) | Redis key name | ### Request Example ```python from redis import Redis from pottery import HyperLogLog redis = Redis() # Create HyperLogLog to track unique searches searches = HyperLogLog(redis=redis, key='daily-searches') ``` ### Response None ``` -------------------------------- ### Basic RedisDict Usage Source: https://github.com/brainix/pottery/blob/master/README.md Demonstrates creating and manipulating a RedisDict, a dictionary-like container backed by Redis. Keys and values must be JSON serializable. ```python from pottery import RedisDict tel = RedisDict({'jack': 4098, 'sape': 4139}, redis=redis, key='tel') tel['guido'] = 4127 print(tel) tel['jack'] del tel['sape'] tel['irv'] = 4127 print(tel) list(tel) sorted(tel) 'guido' in tel 'jack' not in tel ``` -------------------------------- ### Dictionary Methods Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-counter.md RedisCounter supports standard dictionary methods such as membership checking, iteration over keys, retrieving items, and getting the length, inherited from `RedisDict`. ```APIDOC ### Dictionary Methods RedisCounter supports standard dict methods (inherited from RedisDict): ```python # Check membership if 'red' in c: print('Found') # Iterate over keys for key in c: print(key) # Get all items for key, count in c.items(): print(f'{key}: {count}') # Get length print(len(c)) ``` ``` -------------------------------- ### Create a HyperLogLog Source: https://github.com/brainix/pottery/blob/master/README.md Instantiate a HyperLogLog object, specifying the Redis connection and a unique key. ```python >>> from pottery import HyperLogLog >>> google_searches = HyperLogLog(redis=redis, key='google-searches') >>> ``` -------------------------------- ### Get N Most Common Elements Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-counter.md Returns the n most common elements and their counts, ordered from most common to least common. O(n log n) complexity. ```python def most_common(self, n: int | None = None) -> list[tuple[JSONTypes, int]] ``` ```python RedisCounter('abracadabra', redis=redis, key='my-counter').most_common(3) # [('a', 5), ('b', 2), ('r', 2)] ``` -------------------------------- ### Initialize Redlock Source: https://github.com/brainix/pottery/blob/master/_autodocs/redlock.md Instantiate a Redlock with a key, Redis master instances, and optional parameters for auto-release time and context manager behavior. It's recommended to use 5 Redis masters in production. ```python from redis import Redis from pottery import Redlock redis1 = Redis.from_url('redis://localhost:6379/0') redis2 = Redis.from_url('redis://localhost:6380/0') redis3 = Redis.from_url('redis://localhost:6381/0') printer_lock = Redlock( key='printer', masters={redis1, redis2, redis3}, auto_release_time=10.0 ) ``` -------------------------------- ### Measuring Multiple Intervals Source: https://github.com/brainix/pottery/blob/master/_autodocs/context-timer.md Measures the duration of sequential operations by recording elapsed time at different points using ContextTimer's start() and elapsed() methods. ```python import time from pottery import ContextTimer timer = ContextTimer() timer.start() operations = [] time.sleep(0.1) op1_time = timer.elapsed() operations.append(('Load data', op1_time)) time.sleep(0.05) op2_time = timer.elapsed() operations.append(('Process', op2_time - op1_time)) time.sleep(0.03) op3_time = timer.elapsed() operations.append(('Save results', op3_time - op2_time)) timer.stop() for name, duration in operations: print(f'{name}: {duration}ms') ``` -------------------------------- ### Auto-generated Key for Pottery Container Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Shows how to instantiate a Pottery container without specifying a key, resulting in an auto-generated Redis key. The auto-generated key is printed and automatically cleaned up on garbage collection. ```python # Auto-generated key d = RedisDict(redis=redis) print(d.key) # 'pottery:...' ``` -------------------------------- ### Using REDIS_URL for Pottery Container Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Shows how to set the REDIS_URL environment variable and then instantiate a Pottery container without explicitly passing a Redis client, causing it to use the environment variable. ```python import os os.environ['REDIS_URL'] = 'redis://prod.redis.example.com:6379/0' from pottery import RedisDict # Now uses production Redis d = RedisDict(redis=None, key='data') # Uses REDIS_URL ``` -------------------------------- ### Initialize BloomFilter Source: https://github.com/brainix/pottery/blob/master/_autodocs/bloom-filter.md Create a BloomFilter instance expecting a certain number of elements with a specified false positive rate. Requires a Redis client and a key name. ```python from redis import Redis from pottery import BloomFilter redis = Redis() # Create filter expecting ~100 unique users # With 1% false positive rate users = BloomFilter( num_elements=100, false_positives=0.01, redis=redis, key='seen-users' ) ``` -------------------------------- ### Get approximate size of BloomFilter Source: https://github.com/brainix/pottery/blob/master/_autodocs/bloom-filter.md Retrieve the approximate number of elements added to the Bloom filter. This operation has O(1) complexity and provides an estimate, not an exact count. ```python users.add('alice') print(len(users)) # 1 users.update(['bob', 'charlie']) print(len(users)) # ~3 (approximate) ``` -------------------------------- ### RedisDict Common Parameters Source: https://github.com/brainix/pottery/blob/master/_autodocs/README.md Demonstrates common parameters for initializing a RedisDict container. The redis client is optional, defaulting to REDIS_URL, and the key is optional, auto-generated if omitted. ```python from pottery import RedisDict # Common parameters container = RedisDict( redis=redis, # Redis client (optional, uses REDIS_URL by default) key='my-key' # Redis key name (optional, auto-generated if omitted) ) ``` -------------------------------- ### RedisSet Operations Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-set.md Demonstrates union, intersection, difference, and symmetric difference operations on RedisSet objects. Ensure Redis is initialized and accessible. ```python a = RedisSet('abracadabra', redis=redis, key='magic_a') b = set('alacazam') # Difference difference = a - b # {'b', 'd', 'r'} # Union union = a | b # {'a', 'b', 'c', 'd', 'l', 'm', 'r', 'z'} # Intersection intersection = a & b # {'a', 'c'} # Symmetric difference sym_diff = a ^ b # {'b', 'd', 'l', 'm', 'r', 'z'} ``` -------------------------------- ### CachedOrderedDict with Cache Hits and Misses Source: https://github.com/brainix/pottery/blob/master/README.md Demonstrates a scenario with a mix of cache hits and misses. Keys present in the cache are retrieved directly, while new keys are populated. ```python search_results_2 = CachedOrderedDict( redis_client=redis, redis_key='search-results', dict_keys=(2, 4, 6, 8, 10), ) sorted(search_results_2.misses()) search_results_2[2] search_results_2[6] = 'six' search_results_2[8] = 'eight' search_results_2[10] = 'ten' sorted(search_results_2.misses()) for key, value in search_results_2.items(): print(f'{key}: {value}') ``` -------------------------------- ### Get Approximate Cardinality of HyperLogLog Source: https://github.com/brainix/pottery/blob/master/_autodocs/hyperloglog.md Retrieve the approximate number of distinct elements stored in the HyperLogLog. This operation has O(1) complexity and provides a result within approximately 2% error. ```python searches.add('sonic the hedgehog video game') print(len(searches)) # 1 searches.update({ 'google in 1998', 'minesweeper', 'joey tribbiani', 'wizard of oz', 'rgb to hex', 'pac-man', 'breathing exercise', 'do a barrel roll', 'snake', }) print(len(searches)) # ~10 ``` -------------------------------- ### RedisDict Constructor Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-dict.md Initializes a RedisDict instance. It can be populated with initial data from a mapping or an iterable of tuples. You can specify a Redis client instance and a key name for the Redis hash. ```APIDOC ## RedisDict Constructor ### Description Initializes a RedisDict. Accepts an optional initial mapping or iterable of key-value pairs, a Redis client instance, and a Redis key name. Additional keyword arguments are treated as key-value pairs to be stored. ### Signature ```python def __init__(self, arg: InitArg = tuple(), *, redis: Redis | None = None, key: str = '', **kwargs: JSONTypes) -> None ``` ### Parameters #### Arguments - **arg** (InitArg) - Optional - Initial mapping data or iterable of tuples. - **redis** (Redis) - Optional - Redis client instance. Defaults to the default Redis client. - **key** (str) - Optional - The Redis key name for the hash. Defaults to an auto-generated key. - **kwargs** (JSONTypes) - Optional - Additional key-value pairs to initialize the dictionary with. ### Raises - **KeyExistsError**: If the specified Redis key already exists. ### Example ```python from redis import Redis from pottery import RedisDict redis_client = Redis.from_url('redis://localhost:6379/0') my_dict = RedisDict({'a': 1, 'b': 2}, redis=redis_client, key='my_redis_dict') ``` ``` -------------------------------- ### Populate CachedOrderedDict Source: https://github.com/brainix/pottery/blob/master/README.md Populate the cache by assigning values to keys. Initially, all keys are misses. After assignment, there are no misses. ```python sorted(search_results_1.misses()) search_results_1[1] = 'one' search_results_1[2] = 'two' search_results_1[3] = 'three' search_results_1[4] = 'four' search_results_1[5] = 'five' sorted(search_results_1.misses()) ``` -------------------------------- ### Stand-alone ContextTimer Usage Source: https://github.com/brainix/pottery/blob/master/README.md Use ContextTimer to start, stop, and measure elapsed time. The elapsed() method returns time in milliseconds. Ensure time.sleep() calls are sufficient to observe measurable differences. ```python >>> import time >>> from pottery import ContextTimer >>> timer = ContextTimer() >>> timer.start() >>> time.sleep(0.1) >>> 100 <= timer.elapsed() < 200 True >>> timer.stop() >>> time.sleep(0.1) >>> 100 <= timer.elapsed() < 200 True >>> ``` -------------------------------- ### Redis Connection Pooling with Pottery Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Demonstrates setting up a shared Redis connection pool for high-throughput applications. This optimizes performance by reusing connections across multiple Redis clients and Pottery instances. ```python from redis import Redis, ConnectionPool # Single shared pool for all connections pool = ConnectionPool.from_url( 'redis://localhost:6379/0', max_connections=50, socket_timeout=1, socket_keepalive=True ) # Use across multiple clients redis1 = Redis(connection_pool=pool) redis2 = Redis(connection_pool=pool) d = RedisDict(redis=redis1, key='data') ``` -------------------------------- ### Instantiate CachedOrderedDict Source: https://github.com/brainix/pottery/blob/master/README.md Instantiate CachedOrderedDict with a Redis client, a Redis key for the backing hash, and an ordered iterable of keys to be looked up or populated. ```python from pottery import CachedOrderedDict search_results_1 = CachedOrderedDict( redis_client=redis, redis_key='search-results', dict_keys=(1, 2, 3, 4, 5), ) ``` -------------------------------- ### QuorumNotAchieved Exception Example Source: https://github.com/brainix/pottery/blob/master/_autodocs/errors.md Demonstrates handling the QuorumNotAchieved exception when a consensus-based algorithm fails to achieve quorum across Redis masters. This typically occurs during lock acquisition or ID increment operations. ```python from pottery import Redlock, QuorumNotAchieved from redis import Redis redis1 = Redis.from_url('redis://localhost:6379/0') redis2 = Redis.from_url('redis://localhost:6380/0') redis3 = Redis.from_url('redis://localhost:6381/0') lock = Redlock(key='resource', masters={redis1, redis2, redis3}) try: if not lock.acquire(timeout=5.0): print('Could not acquire lock') except QuorumNotAchieved as e: print(f'Quorum not achieved on masters: {list(e.masters)}') if e.redis_errors: for err in e.redis_errors: print(f' Redis error: {err}') ``` -------------------------------- ### Generate IDs with Error Handling Source: https://github.com/brainix/pottery/blob/master/_autodocs/nextid.md Demonstrates how to generate IDs using NextID and handle potential QuorumNotAchieved errors. Ensure Redis masters are properly configured and available. ```python from pottery import QuorumNotAchieved tweet_ids = NextID(key='tweet-ids', masters={redis1, redis2, redis3}) try: tweet_id = next(tweet_ids) except QuorumNotAchieved as e: print(f'Could not achieve quorum on {e.masters}') # Handle failure - maybe retry, use local generator, etc. ``` -------------------------------- ### Explicit Redis Client for Pottery Container Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Illustrates how to explicitly provide a Redis client instance to a Pottery container, overriding any default or environment variable settings. ```python from redis import Redis from pottery import RedisDict # Explicit Redis client redis = Redis.from_url('redis://localhost:6379/1') d = RedisDict(redis=redis, key='mydata') ``` -------------------------------- ### Configure Redis Connection for Pottery Source: https://github.com/brainix/pottery/blob/master/_autodocs/API-INDEX.md Configure the default Redis connection for Pottery by setting the REDIS_URL environment variable. Alternatively, create an explicit Redis client instance. The RedisDict will automatically use the REDIS_URL if not otherwise specified. ```python import os from redis import Redis from pottery import RedisDict # Configure default Redis connection os.environ['REDIS_URL'] = 'redis://localhost:6379/0' # Or create explicit client redis = Redis.from_url('redis://localhost:6379/0') # Use anywhere in your app data = RedisDict(key='my-data') # Uses REDIS_URL ``` -------------------------------- ### Get Element by Index or Slice Source: https://github.com/brainix/pottery/blob/master/_autodocs/redis-list.md Retrieve a single element using an integer index or multiple elements using a slice. O(1) for head/tail indices, O(n) for others. Emits InefficientAccessWarning for non-head/tail access. ```python print(squares[0]) print(squares[-1]) print(squares[1:3]) ``` -------------------------------- ### Explicit Key for Pottery Container Source: https://github.com/brainix/pottery/blob/master/_autodocs/configuration.md Illustrates how to specify an explicit Redis key name when creating a Pottery container. ```python d = RedisDict(redis=redis, key='my-specific-key') ```