Upgrading limits 3 to 4
Breaking3.14.1 → 4.8.0Breaking1Security1Platform1Deprecated2New4Changed1Fixed3Other6
BreakingUpgrade verdict
1 breaking change and a platform requirement change and a security fix.
In plain terms
- The reset time returned by the window stats now includes fractions of a second instead of being rounded down to a whole second, so code that expects whole seconds may need updating.
- Python 3.9 is no longer supported; you need a newer Python version to use this release.
- The package is now published to PyPI using a more secure, token-free publishing method.
- Support for using etcd as a storage backend is being phased out.
Must act 5 items need code or config changes
Python requirement changed in 4.3: >=3.9 → >=3.10.
What you must change
Breaking1
Changes the definition of reset_time in get_window_stats to use a precise floating point value instead of truncating to the previous second.
reset_timeget_window_statsSecurity1
Changes the PyPI release process to use trusted publishing.
Platform1
Drops support for Python 3.9.
Deprecations to plan for
Deprecated2
Deprecates support for etcd.
etcdDeprecates the Fixed window with elastic expiry strategy.
API changes
Generated by DepDelta from published Python source. Not mixed with prose notes.
- added:
export SlidingWindowCounterSupport
- removed:
property Storage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
async method MovingWindowSupport.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] → async method MovingWindowSupport.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - changed:
async method Storage.get_expiry(key: str) -> int → async method Storage.get_expiry(key: str) -> float - changed:
async method Storage.reset() -> Optional[int] → async method Storage.reset() -> int | None - changed:
constructor Storage(uri: Optional[str]=…, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor Storage(uri: str | None=…, wrap_exceptions: bool=…, **options: float | str | bool) -> None - changed:
field Storage.STORAGE_SCHEME: Optional[List[str]] → field Storage.STORAGE_SCHEME: list[str] | None - added:
async method SlidingWindowCounterSupport.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method SlidingWindowCounterSupport.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
class SlidingWindowCounterSupport(ABC) - added:
property Storage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
property EtcdStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
async method EtcdStorage.get_expiry(key: str) -> int → async method EtcdStorage.get_expiry(key: str) -> float - changed:
async method EtcdStorage.reset() -> Optional[int] → async method EtcdStorage.reset() -> int | None - changed:
constructor EtcdStorage(uri: str, max_retries: int=…, **options: str) -> None → constructor EtcdStorage(uri: str, max_retries: int=…, wrap_exceptions: bool=…, **options: str) -> None - added:
property EtcdStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
property MemcachedStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
async method MemcachedStorage.get_expiry(key: str) -> int → async method MemcachedStorage.get_expiry(key: str) -> float - changed:
async method MemcachedStorage.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int → async method MemcachedStorage.incr(key: str, expiry: float, elastic_expiry: bool=…, amount: int=…, set_expiration_key: bool=…) -> int - changed:
async method MemcachedStorage.reset() -> Optional[int] → async method MemcachedStorage.reset() -> int | None - changed:
class MemcachedStorage(Storage) → class MemcachedStorage(Storage, SlidingWindowCounterSupport, TimestampedSlidingWindow) - changed:
constructor MemcachedStorage(uri: str, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor MemcachedStorage(uri: str, wrap_exceptions: bool=…, **options: float | str | bool) -> None - added:
async method MemcachedStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method MemcachedStorage.decr(key: str, amount: int=…, noreply: bool=…) -> int - added:
async method MemcachedStorage.get_many(keys: Iterable[str]) -> dict[bytes, ItemP] - added:
async method MemcachedStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
property MemcachedStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
class LockableEntry(asyncio.Lock) - removed:
constructor LockableEntry(expiry: int) -> None - removed:
property MemoryStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
async method MemoryStorage.get_expiry(key: str) -> int → async method MemoryStorage.get_expiry(key: str) -> float - changed:
async method MemoryStorage.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] → async method MemoryStorage.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - changed:
async method MemoryStorage.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int → async method MemoryStorage.incr(key: str, expiry: float, elastic_expiry: bool=…, amount: int=…) -> int - changed:
async method MemoryStorage.reset() -> Optional[int] → async method MemoryStorage.reset() -> int | None - changed:
class MemoryStorage(Storage, MovingWindowSupport) → class MemoryStorage(Storage, MovingWindowSupport, SlidingWindowCounterSupport, TimestampedSlidingWindow) - changed:
constructor MemoryStorage(uri: Optional[str]=…, wrap_exceptions: bool=…, **_: str) -> None → constructor MemoryStorage(uri: str | None=…, wrap_exceptions: bool=…, **_: str) -> None - added:
async method MemoryStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method MemoryStorage.decr(key: str, amount: int=…) -> int - added:
async method MemoryStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
class Entry - added:
constructor Entry(expiry: int) -> None - added:
property MemoryStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
property MongoDBStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
async method MongoDBStorage.get_expiry(key: str) -> int → async method MongoDBStorage.get_expiry(key: str) -> float - changed:
async method MongoDBStorage.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] → async method MongoDBStorage.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - changed:
async method MongoDBStorage.reset() -> Optional[int] → async method MongoDBStorage.reset() -> int | None - changed:
class MongoDBStorage(Storage, MovingWindowSupport) → class MongoDBStorage(Storage, MovingWindowSupport, SlidingWindowCounterSupport) - changed:
constructor MongoDBStorage(uri: str, database_name: str=…, counter_collection_name: str=…, window_collection_name: str=…, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor MongoDBStorage(uri: str, database_name: str=…, counter_collection_name: str=…, window_collection_name: str=…, wrap_exceptions: bool=…, **options: float | str | bool) -> None - added:
async method MongoDBStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method MongoDBStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
property MongoDBStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
async method RedisInteractor.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] - removed:
async method RedisSentinelStorage.check() -> bool - removed:
async method RedisSentinelStorage.get(key: str) -> int - removed:
async method RedisSentinelStorage.get_expiry(key: str) -> int - removed:
class RedisInteractor - removed:
field RedisClusterStorage.DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] - removed:
field RedisInteractor.PREFIX - removed:
field RedisInteractor.RES_DIR - removed:
field RedisInteractor.SCRIPT_ACQUIRE_MOVING_WINDOW - removed:
field RedisInteractor.SCRIPT_CLEAR_KEYS - removed:
field RedisInteractor.SCRIPT_INCR_EXPIRE - removed:
field RedisInteractor.SCRIPT_MOVING_WINDOW - removed:
field RedisInteractor.lua_acquire_window: coredis.commands.Script[bytes] - removed:
field RedisInteractor.lua_clear_keys: coredis.commands.Script[bytes] - removed:
field RedisInteractor.lua_incr_expire: coredis.commands.Script[bytes] - removed:
field RedisInteractor.lua_moving_window: coredis.commands.Script[bytes] - removed:
method RedisInteractor.prefixed_key(key: str) -> str - removed:
method RedisStorage.initialize_storage(_uri: str) -> None - removed:
property RedisStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
async method RedisClusterStorage.reset() -> Optional[int] → async method RedisClusterStorage.reset() -> int | None - changed:
async method RedisStorage.get_expiry(key: str) -> int → async method RedisStorage.get_expiry(key: str) -> float - changed:
async method RedisStorage.reset() -> Optional[int] → async method RedisStorage.reset() -> int | None - changed:
class RedisStorage(RedisInteractor, Storage, MovingWindowSupport) → class RedisStorage(Storage, MovingWindowSupport, SlidingWindowCounterSupport) - changed:
constructor RedisClusterStorage(uri: str, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor RedisClusterStorage(uri: str, wrap_exceptions: bool=…, implementation: Literal['redispy', 'coredis', 'valkey']=…, key_prefix: str=…, **options: float | str | bool) -> None - changed:
constructor RedisSentinelStorage(uri: str, service_name: Optional[str]=…, use_replicas: bool=…, sentinel_kwargs: Optional[Dict[str, Union[float, str, bool]]]=…, **options: Union[float, str, bool]) → constructor RedisSentinelStorage(uri: str, wrap_exceptions: bool=…, implementation: Literal['redispy', 'coredis', 'valkey']=…, key_prefix: str=…, service_name: str | None=…, use_replicas: bool=…, sentinel_kwargs: dict[str, float | str | bool] | None=…, **options: float | str | bool) - changed:
constructor RedisStorage(uri: str, connection_pool: Optional[coredis.ConnectionPool]=…, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor RedisStorage(uri: str, wrap_exceptions: bool=…, implementation: Literal['redispy', 'coredis', 'valkey']=…, key_prefix: str=…, **options: float | str | bool) -> None - added:
async method RedisStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method RedisStorage.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - added:
async method RedisStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
export CoredisBridge - added:
export Literal - added:
export MovingWindowSupport - added:
export RedisBridge - added:
export RedispyBridge - added:
export SlidingWindowCounterSupport - added:
export Storage - added:
export ValkeyBridge - added:
field RedisClusterStorage.MODE - added:
field RedisSentinelStorage.MODE - added:
field RedisStorage.MODE: Literal['BASIC', 'CLUSTER', 'SENTINEL'] - added:
field RedisStorage.PREFIX - added:
field RedisStorage.bridge: RedisBridge - added:
field RedisStorage.storage_exceptions: tuple[Exception, ...] - added:
field RedisStorage.target_server: Literal['redis', 'valkey'] - added:
method RedisClusterStorage.configure_bridge() -> None - added:
method RedisSentinelStorage.configure_bridge() -> None - added:
method RedisStorage.configure_bridge() -> None - added:
property RedisStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- added:
async method RedisBridge.acquire_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method RedisBridge.acquire_sliding_window_entry(previous_key: str, current_key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method RedisBridge.check() -> bool - added:
async method RedisBridge.clear(key: str) -> None - added:
async method RedisBridge.get(key: str) -> int - added:
async method RedisBridge.get_expiry(key: str) -> float - added:
async method RedisBridge.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - added:
async method RedisBridge.get_sliding_window(previous_key: str, current_key: str, expiry: int) -> tuple[int, float, int, float] - added:
async method RedisBridge.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int - added:
async method RedisBridge.lua_reset() -> int | None - added:
async method RedisBridge.reset() -> int | None - added:
class RedisBridge(ABC) - added:
constructor RedisBridge(uri: str, dependency: ModuleType, key_prefix: str) -> None - added:
field RedisBridge.RES_DIR - added:
field RedisBridge.SCRIPT_ACQUIRE_MOVING_WINDOW - added:
field RedisBridge.SCRIPT_ACQUIRE_SLIDING_WINDOW - added:
field RedisBridge.SCRIPT_CLEAR_KEYS - added:
field RedisBridge.SCRIPT_INCR_EXPIRE - added:
field RedisBridge.SCRIPT_MOVING_WINDOW - added:
field RedisBridge.SCRIPT_SLIDING_WINDOW - added:
method RedisBridge.prefixed_key(key: str) -> str - added:
method RedisBridge.register_scripts() -> None - added:
method RedisBridge.use_basic(**options: str | float | bool) -> None - added:
method RedisBridge.use_cluster(**options: str | float | bool) -> None - added:
method RedisBridge.use_sentinel(service_name: str | None, use_replicas: bool, sentinel_kwargs: dict[str, str | float | bool] | None, **options: str | float | bool) -> None - added:
property RedisBridge.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- added:
async method CoredisBridge.acquire_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method CoredisBridge.acquire_sliding_window_entry(previous_key: str, current_key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method CoredisBridge.check() -> bool - added:
async method CoredisBridge.clear(key: str) -> None - added:
async method CoredisBridge.get(key: str) -> int - added:
async method CoredisBridge.get_expiry(key: str) -> float - added:
async method CoredisBridge.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - added:
async method CoredisBridge.get_sliding_window(previous_key: str, current_key: str, expiry: int) -> tuple[int, float, int, float] - added:
async method CoredisBridge.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int - added:
async method CoredisBridge.lua_reset() -> int | None - added:
async method CoredisBridge.reset() -> int | None - added:
class CoredisBridge(RedisBridge) - added:
field CoredisBridge.DEFAULT_CLUSTER_OPTIONS: dict[str, float | str | bool] - added:
field CoredisBridge.connection_getter: Callable[[bool], AsyncCoRedisClient] - added:
field CoredisBridge.lua_acquire_moving_window: coredis.commands.Script[bytes] - added:
field CoredisBridge.lua_acquire_sliding_window: coredis.commands.Script[bytes] - added:
field CoredisBridge.lua_clear_keys: coredis.commands.Script[bytes] - added:
field CoredisBridge.lua_incr_expire: coredis.commands.Script[bytes] - added:
field CoredisBridge.lua_moving_window: coredis.commands.Script[bytes] - added:
field CoredisBridge.lua_sliding_window: coredis.commands.Script[bytes] - added:
method CoredisBridge.get_connection(readonly: bool=…) -> AsyncCoRedisClient - added:
method CoredisBridge.register_scripts() -> None - added:
method CoredisBridge.use_basic(**options: str | float | bool) -> None - added:
method CoredisBridge.use_cluster(**options: str | float | bool) -> None - added:
method CoredisBridge.use_sentinel(service_name: str | None, use_replicas: bool, sentinel_kwargs: dict[str, str | float | bool] | None, **options: str | float | bool) -> None - added:
property CoredisBridge.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- added:
async method RedispyBridge.acquire_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method RedispyBridge.acquire_sliding_window_entry(previous_key: str, current_key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
async method RedispyBridge.check() -> bool - added:
async method RedispyBridge.clear(key: str) -> None - added:
async method RedispyBridge.get(key: str) -> int - added:
async method RedispyBridge.get_expiry(key: str) -> float - added:
async method RedispyBridge.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - added:
async method RedispyBridge.get_sliding_window(previous_key: str, current_key: str, expiry: int) -> tuple[int, float, int, float] - added:
async method RedispyBridge.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int - added:
async method RedispyBridge.lua_reset() -> int | None - added:
async method RedispyBridge.reset() -> int | None - added:
class RedispyBridge(RedisBridge) - added:
field RedispyBridge.DEFAULT_CLUSTER_OPTIONS: dict[str, float | str | bool] - added:
field RedispyBridge.connection_getter: Callable[[bool], AsyncRedisClient] - added:
field RedispyBridge.lua_acquire_moving_window: redis.commands.core.Script - added:
field RedispyBridge.lua_acquire_sliding_window: redis.commands.core.Script - added:
field RedispyBridge.lua_clear_keys: redis.commands.core.Script - added:
field RedispyBridge.lua_incr_expire: redis.commands.core.Script - added:
field RedispyBridge.lua_moving_window: redis.commands.core.Script - added:
field RedispyBridge.lua_sliding_window: redis.commands.core.Script - added:
method RedispyBridge.get_connection(readonly: bool=…) -> AsyncRedisClient - added:
method RedispyBridge.register_scripts() -> None - added:
method RedispyBridge.use_basic(**options: str | float | bool) -> None - added:
method RedispyBridge.use_cluster(**options: str | float | bool) -> None - added:
method RedispyBridge.use_sentinel(service_name: str | None, use_replicas: bool, sentinel_kwargs: dict[str, str | float | bool] | None, **options: str | float | bool) -> None - added:
property RedispyBridge.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- added:
class ValkeyBridge(RedispyBridge) - added:
property ValkeyBridge.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- added:
async method SlidingWindowCounterRateLimiter.get_window_stats(item: RateLimitItem, *identifiers: str) -> WindowStats - added:
async method SlidingWindowCounterRateLimiter.hit(item: RateLimitItem, *identifiers: str, cost: int=…) -> bool - added:
async method SlidingWindowCounterRateLimiter.test(item: RateLimitItem, *identifiers: str, cost: int=…) -> bool - added:
class SlidingWindowCounterRateLimiter(RateLimiter) - added:
constructor SlidingWindowCounterRateLimiter(storage: StorageTypes)
- changed:
constructor RateLimitItem(amount: int, multiples: Optional[int]=…, namespace: str=…) → constructor RateLimitItem(amount: int, multiples: int | None=…, namespace: str=…) - changed:
function safe_string(value: Union[bytes, str, int]) -> str → function safe_string(value: bytes | str | int | float) -> str - changed:
method RateLimitItem.key_for(*identifiers: str) -> str → method RateLimitItem.key_for(*identifiers: bytes | str | int | float) -> str - changed:
variable GRANULARITIES: Dict[str, Type[RateLimitItem]] → variable GRANULARITIES: dict[str, type[RateLimitItem]]
- changed:
function storage_from_string(storage_string: str, **options: Union[float, str, bool]) -> StorageTypes → function storage_from_string(storage_string: str, **options: float | str | bool) -> StorageTypes - added:
export SlidingWindowCounterSupport
- removed:
property Storage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
constructor Storage(uri: Optional[str]=…, wrap_exceptions: bool=…, **options: Union[float, str, bool]) → constructor Storage(uri: str | None=…, wrap_exceptions: bool=…, **options: float | str | bool) - changed:
field Storage.STORAGE_SCHEME: Optional[List[str]] → field Storage.STORAGE_SCHEME: list[str] | None - changed:
method MovingWindowSupport.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] → method MovingWindowSupport.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - changed:
method Storage.get_expiry(key: str) -> int → method Storage.get_expiry(key: str) -> float - changed:
method Storage.reset() -> Optional[int] → method Storage.reset() -> int | None - added:
class SlidingWindowCounterSupport(ABC) - added:
class TimestampedSlidingWindow - added:
method SlidingWindowCounterSupport.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
method SlidingWindowCounterSupport.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
property Storage.base_exceptions -> type[Exception] | tuple[type[Exception], ...] - added:
static method TimestampedSlidingWindow.sliding_window_keys(key: str, expiry: int, at: float) -> tuple[str, str]
- removed:
property EtcdStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
constructor EtcdStorage(uri: str, max_retries: int=…, **options: str) -> None → constructor EtcdStorage(uri: str, max_retries: int=…, wrap_exceptions: bool=…, **options: str) -> None - changed:
method EtcdStorage.get_expiry(key: str) -> int → method EtcdStorage.get_expiry(key: str) -> float - changed:
method EtcdStorage.reset() -> Optional[int] → method EtcdStorage.reset() -> int | None - added:
property EtcdStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
property MemcachedStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
class MemcachedStorage(Storage) → class MemcachedStorage(Storage, SlidingWindowCounterSupport, TimestampedSlidingWindow) - changed:
constructor MemcachedStorage(uri: str, wrap_exceptions: bool=…, **options: Union[str, Callable[[], MemcachedClientP]]) -> None → constructor MemcachedStorage(uri: str, wrap_exceptions: bool=…, **options: str | Callable[[], MemcachedClientP]) -> None - changed:
method MemcachedStorage.get_client(module: ModuleType, hosts: List[Tuple[str, int]], **kwargs: str) -> MemcachedClientP → method MemcachedStorage.get_client(module: ModuleType, hosts: list[tuple[str, int]], **kwargs: str) -> MemcachedClientP - changed:
method MemcachedStorage.get_expiry(key: str) -> int → method MemcachedStorage.get_expiry(key: str) -> float - changed:
method MemcachedStorage.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int → method MemcachedStorage.incr(key: str, expiry: float, elastic_expiry: bool=…, amount: int=…, set_expiration_key: bool=…) -> int - changed:
method MemcachedStorage.reset() -> Optional[int] → method MemcachedStorage.reset() -> int | None - added:
method MemcachedStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
method MemcachedStorage.get_many(keys: Iterable[str]) -> dict[str, Any] - added:
method MemcachedStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
property MemcachedStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
class LockableEntry(threading._RLock) - removed:
constructor LockableEntry(expiry: float) -> None - removed:
property MemoryStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
class MemoryStorage(Storage, MovingWindowSupport) → class MemoryStorage(Storage, MovingWindowSupport, SlidingWindowCounterSupport, TimestampedSlidingWindow) - changed:
constructor MemoryStorage(uri: Optional[str]=…, wrap_exceptions: bool=…, **_: str) → constructor MemoryStorage(uri: str | None=…, wrap_exceptions: bool=…, **_: str) - changed:
method MemoryStorage.get_expiry(key: str) -> int → method MemoryStorage.get_expiry(key: str) -> float - changed:
method MemoryStorage.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] → method MemoryStorage.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - changed:
method MemoryStorage.incr(key: str, expiry: int, elastic_expiry: bool=…, amount: int=…) -> int → method MemoryStorage.incr(key: str, expiry: float, elastic_expiry: bool=…, amount: int=…) -> int - changed:
method MemoryStorage.reset() -> Optional[int] → method MemoryStorage.reset() -> int | None - added:
class Entry - added:
constructor Entry(expiry: float) -> None - added:
method MemoryStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
method MemoryStorage.decr(key: str, amount: int=…) -> int - added:
method MemoryStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
property MemoryStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
property MongoDBStorageBase.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
class MongoDBStorageBase(Storage, MovingWindowSupport, ABC) → class MongoDBStorageBase(Storage, MovingWindowSupport, SlidingWindowCounterSupport, ABC) - changed:
constructor MongoDBStorageBase(uri: str, database_name: str=…, counter_collection_name: str=…, window_collection_name: str=…, wrap_exceptions: bool=…, **options: Union[int, str, bool]) -> None → constructor MongoDBStorageBase(uri: str, database_name: str=…, counter_collection_name: str=…, window_collection_name: str=…, wrap_exceptions: bool=…, **options: int | str | bool) -> None - changed:
method MongoDBStorageBase.get_expiry(key: str) -> int → method MongoDBStorageBase.get_expiry(key: str) -> float - changed:
method MongoDBStorageBase.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] → method MongoDBStorageBase.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - changed:
method MongoDBStorageBase.reset() -> Optional[int] → method MongoDBStorageBase.reset() -> int | None - added:
method MongoDBStorageBase.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
method MongoDBStorageBase.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
property MongoDBStorageBase.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- removed:
class RedisInteractor - removed:
field RedisInteractor.PREFIX - removed:
field RedisInteractor.RES_DIR - removed:
field RedisInteractor.SCRIPT_ACQUIRE_MOVING_WINDOW - removed:
field RedisInteractor.SCRIPT_CLEAR_KEYS - removed:
field RedisInteractor.SCRIPT_INCR_EXPIRE - removed:
field RedisInteractor.SCRIPT_MOVING_WINDOW - removed:
field RedisInteractor.lua_acquire_window: ScriptP[bool] - removed:
field RedisInteractor.lua_moving_window: ScriptP[Tuple[int, int]] - removed:
method RedisInteractor.get_moving_window(key: str, limit: int, expiry: int) -> Tuple[int, int] - removed:
method RedisInteractor.prefixed_key(key: str) -> str - removed:
property RedisStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
class RedisStorage(RedisInteractor, Storage, MovingWindowSupport) → class RedisStorage(Storage, MovingWindowSupport, SlidingWindowCounterSupport) - changed:
constructor RedisStorage(uri: str, connection_pool: Optional[redis.connection.ConnectionPool]=…, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor RedisStorage(uri: str, connection_pool: redis.connection.ConnectionPool | None=…, key_prefix: str=…, wrap_exceptions: bool=…, **options: float | str | bool) -> None - changed:
method RedisStorage.get_expiry(key: str) -> int → method RedisStorage.get_expiry(key: str) -> float - changed:
method RedisStorage.reset() -> Optional[int] → method RedisStorage.reset() -> int | None - added:
field RedisStorage.PREFIX - added:
field RedisStorage.RES_DIR - added:
field RedisStorage.SCRIPT_ACQUIRE_MOVING_WINDOW - added:
field RedisStorage.SCRIPT_ACQUIRE_SLIDING_WINDOW - added:
field RedisStorage.SCRIPT_CLEAR_KEYS - added:
field RedisStorage.SCRIPT_INCR_EXPIRE - added:
field RedisStorage.SCRIPT_MOVING_WINDOW - added:
field RedisStorage.SCRIPT_SLIDING_WINDOW - added:
field RedisStorage.lua_acquire_moving_window: redis.commands.core.Script - added:
field RedisStorage.lua_acquire_sliding_window: redis.commands.core.Script - added:
field RedisStorage.lua_moving_window: redis.commands.core.Script - added:
field RedisStorage.lua_sliding_window: redis.commands.core.Script - added:
field RedisStorage.target_server: Literal['redis', 'valkey'] - added:
method RedisStorage.acquire_sliding_window_entry(key: str, limit: int, expiry: int, amount: int=…) -> bool - added:
method RedisStorage.get_connection(readonly: bool=…) -> RedisClient - added:
method RedisStorage.get_moving_window(key: str, limit: int, expiry: int) -> tuple[float, int] - added:
method RedisStorage.get_sliding_window(key: str, expiry: int) -> tuple[int, float, int, float] - added:
method RedisStorage.prefixed_key(key: str) -> str - added:
property RedisStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- changed:
constructor RedisClusterStorage(uri: str, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor RedisClusterStorage(uri: str, key_prefix: str=…, wrap_exceptions: bool=…, **options: float | str | bool) -> None - changed:
field RedisClusterStorage.DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] → field RedisClusterStorage.DEFAULT_OPTIONS: dict[str, float | str | bool] - changed:
method RedisClusterStorage.reset() -> Optional[int] → method RedisClusterStorage.reset() -> int | None
- removed:
method RedisSentinelStorage.check() -> bool - removed:
method RedisSentinelStorage.get(key: str) -> int - removed:
method RedisSentinelStorage.get_expiry(key: str) -> int - removed:
property RedisSentinelStorage.base_exceptions -> Union[Type[Exception], Tuple[Type[Exception], ...]] - changed:
constructor RedisSentinelStorage(uri: str, service_name: Optional[str]=…, use_replicas: bool=…, sentinel_kwargs: Optional[Dict[str, Union[float, str, bool]]]=…, wrap_exceptions: bool=…, **options: Union[float, str, bool]) -> None → constructor RedisSentinelStorage(uri: str, service_name: str | None=…, use_replicas: bool=…, sentinel_kwargs: dict[str, float | str | bool] | None=…, key_prefix: str=…, wrap_exceptions: bool=…, **options: float | str | bool) -> None - added:
method RedisSentinelStorage.get_connection(readonly: bool=…) -> RedisClient - added:
property RedisSentinelStorage.base_exceptions -> type[Exception] | tuple[type[Exception], ...]
- changed:
variable SCHEMES: Dict[str, StorageRegistry] → variable SCHEMES: dict[str, StorageRegistry]
- changed:
variable STRATEGIES: Dict[str, KnownStrategy] → variable STRATEGIES: dict[str, KnownStrategy] - added:
class SlidingWindowCounterRateLimiter(RateLimiter) - added:
constructor SlidingWindowCounterRateLimiter(storage: StorageTypes) - added:
method SlidingWindowCounterRateLimiter.get_window_stats(item: RateLimitItem, *identifiers: str) -> WindowStats - added:
method SlidingWindowCounterRateLimiter.hit(item: RateLimitItem, *identifiers: str, cost: int=…) -> bool - added:
method SlidingWindowCounterRateLimiter.test(item: RateLimitItem, *identifiers: str, cost: int=…) -> bool
- removed:
class ScriptP(Protocol[R_co]) - removed:
export Dict - removed:
export List - removed:
export Optional - removed:
export Tuple - removed:
export Type - removed:
export Union - changed:
async method EmcacheClientP.get(key: bytes, return_flags: bool=…) -> Optional[ItemP] → async method EmcacheClientP.get(key: bytes, return_flags: bool=…) -> ItemP | None - changed:
async method EmcacheClientP.gets(key: bytes, return_flags: bool=…) -> Optional[ItemP] → async method EmcacheClientP.gets(key: bytes, return_flags: bool=…) -> ItemP | None - changed:
async method EmcacheClientP.increment(key: bytes, value: int, *, noreply: bool=…) -> Optional[int] → async method EmcacheClientP.increment(key: bytes, value: int, *, noreply: bool=…) -> int | None - changed:
field ItemP.cas: Optional[int] → field ItemP.cas: int | None - changed:
field ItemP.flags: Optional[int] → field ItemP.flags: int | None - changed:
method MemcachedClientP.add(key: str, value: Serializable, expire: Optional[int]=…, noreply: Optional[bool]=…, flags: Optional[int]=…) -> bool → method MemcachedClientP.add(key: str, value: Serializable, expire: int | None=…, noreply: bool | None=…, flags: int | None=…) -> bool - changed:
method MemcachedClientP.delete(key: str, noreply: Optional[bool]=…) -> Optional[bool] → method MemcachedClientP.delete(key: str, noreply: bool | None=…) -> bool | None - changed:
method MemcachedClientP.get(key: str, default: Optional[str]=…) -> bytes → method MemcachedClientP.get(key: str, default: str | None=…) -> bytes - changed:
method MemcachedClientP.incr(key: str, value: int, noreply: Optional[bool]=…) -> int → method MemcachedClientP.incr(key: str, value: int, noreply: bool | None=…) -> int | None - changed:
method MemcachedClientP.set(key: str, value: Serializable, expire: int=…, noreply: Optional[bool]=…, flags: Optional[int]=…) -> bool → method MemcachedClientP.set(key: str, value: Serializable, expire: int=…, noreply: bool | None=…, flags: int | None=…) -> bool - changed:
method MemcachedClientP.touch(key: str, expire: Optional[int]=…, noreply: Optional[bool]=…) -> bool → method MemcachedClientP.touch(key: str, expire: int | None=…, noreply: bool | None=…) -> bool - changed:
variable AsyncRedisClient → variable AsyncRedisClient: TypeAlias - changed:
variable RedisClient → variable RedisClient: TypeAlias - added:
async method EmcacheClientP.decrement(key: bytes, value: int, *, noreply: bool=…) -> int | None - added:
async method EmcacheClientP.get_many(keys: Iterable[bytes]) -> dict[bytes, ItemP] - added:
export Any - added:
export Literal - added:
export TYPE_CHECKING - added:
export TypeAlias - added:
export cast - added:
method MemcachedClientP.decr(key: str, value: int, noreply: bool | None=…) -> int | None - added:
method MemcachedClientP.get_many(keys: Iterable[str]) -> dict[str, Any]
- removed:
field DependencyDict.Missing - changed:
field Dependency.version_found: Optional[Version] → field Dependency.version_found: Version | None - changed:
field Dependency.version_required: Optional[Version] → field Dependency.version_required: Version | None - changed:
field LazyDependency.DEPENDENCIES: Union[Dict[str, Optional[Version]], List[str]] → field LazyDependency.DEPENDENCIES: dict[str, Version | None] | list[str] - changed:
field WindowStats.reset_time: int → field WindowStats.reset_time: float - changed:
function get_dependency(module_path: str) -> Tuple[Optional[ModuleType], Optional[Version]] → function get_dependency(module_path: str) -> tuple[ModuleType, Version | None] - changed:
function granularity_from_string(granularity_string: str) -> Type[RateLimitItem] → function granularity_from_string(granularity_string: str) -> type[RateLimitItem] - changed:
function parse_many(limit_string: str) -> List[RateLimitItem] → function parse_many(limit_string: str) -> list[RateLimitItem] - added:
variable MissingModule