Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-fakeredis for openSUSE:Factory checked in at 2022-02-03 23:16:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-fakeredis (Old) and /work/SRC/openSUSE:Factory/.python-fakeredis.new.1898 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-fakeredis" Thu Feb 3 23:16:20 2022 rev:7 rq:950047 version:1.7.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-fakeredis/python-fakeredis.changes 2021-10-20 20:23:45.349358501 +0200 +++ /work/SRC/openSUSE:Factory/.python-fakeredis.new.1898/python-fakeredis.changes 2022-02-03 23:17:00.248400757 +0100 @@ -1,0 +2,11 @@ +Sun Jan 23 20:36:18 UTC 2022 - Dirk M??ller <dmuel...@suse.com> + +- update to 1.7.0 + * Change a number of corner-case behaviours to match Redis 6.2.6. + * Fix DeprecationWarning for sampling from a set + * Improved support for constructor arguments + * Support redis-py 4 + * Add support for GET option to SET + * PERSIST and EXPIRE should invalidate watches + +------------------------------------------------------------------- Old: ---- fakeredis-1.6.1.tar.gz New: ---- fakeredis-1.7.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-fakeredis.spec ++++++ --- /var/tmp/diff_new_pack.4G2W0P/_old 2022-02-03 23:17:00.804396961 +0100 +++ /var/tmp/diff_new_pack.4G2W0P/_new 2022-02-03 23:17:00.812396906 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-fakeredis # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-fakeredis -Version: 1.6.1 +Version: 1.7.0 Release: 0 Summary: Fake implementation of redis API for testing purposes License: BSD-3-Clause AND MIT ++++++ fakeredis-1.6.1.tar.gz -> fakeredis-1.7.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/.github/workflows/test.yml new/fakeredis-1.7.0/.github/workflows/test.yml --- old/fakeredis-1.6.1/.github/workflows/test.yml 2021-09-08 17:19:01.000000000 +0200 +++ new/fakeredis-1.7.0/.github/workflows/test.yml 2021-11-23 07:07:12.000000000 +0100 @@ -10,7 +10,7 @@ fail-fast: false matrix: python-version: ["3.6", "3.7", "3.8", "3.9", "pypy-3.7"] - redis-py: ["3.5.3"] + redis-py: ["4.0.0"] aioredis: ["2.0.0"] include: - python-version: "3.9" @@ -35,12 +35,12 @@ redis-py: "3.5.3" aioredis: "1.3.1" - python-version: "3.9" - redis-py: "3.5.*" + redis-py: "4.0.*" aioredis: "2.0.0" coverage: yes services: redis: - image: redis:6.0.10 + image: redis:6.2.6 ports: - 6379:6379 steps: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/PKG-INFO new/fakeredis-1.7.0/PKG-INFO --- old/fakeredis-1.6.1/PKG-INFO 2021-09-08 17:25:37.496013600 +0200 +++ new/fakeredis-1.7.0/PKG-INFO 2021-11-28 11:39:31.071334000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fakeredis -Version: 1.6.1 +Version: 1.7.0 Summary: Fake implementation of redis API for testing purposes. Home-page: https://github.com/jamesls/fakeredis Author: James Saryerwinnie @@ -119,7 +119,7 @@ Fakeredis implements the same interface as `redis-py`_, the popular redis client for python, and models the responses -of redis 6.0 (although most new feature in 6.0 are not supported). +of redis 6.2 (although most new features are not supported). Support for aioredis ==================== @@ -476,6 +476,15 @@ Revision history ================ +1.7.0 +----- +- Change a number of corner-case behaviours to match Redis 6.2.6. +- `#310 <https://github.com/jamesls/fakeredis/pull/310>`_ Fix DeprecationWarning for sampling from a set +- `#315 <https://github.com/jamesls/fakeredis/pull/315>`_ Improved support for constructor arguments +- `#316 <https://github.com/jamesls/fakeredis/pull/316>`_ Support redis-py 4 +- `#319 <https://github.com/jamesls/fakeredis/pull/319>`_ Add support for GET option to SET +- `#323 <https://github.com/jamesls/fakeredis/pull/323>`_ PERSIST and EXPIRE should invalidate watches + 1.6.1 ----- - `#305 <https://github.com/jamesls/fakeredis/pull/305>`_ Some packaging modernisation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/README.rst new/fakeredis-1.7.0/README.rst --- old/fakeredis-1.6.1/README.rst 2021-09-08 17:19:58.000000000 +0200 +++ new/fakeredis-1.7.0/README.rst 2021-11-24 06:54:08.000000000 +0100 @@ -95,7 +95,7 @@ Fakeredis implements the same interface as `redis-py`_, the popular redis client for python, and models the responses -of redis 6.0 (although most new feature in 6.0 are not supported). +of redis 6.2 (although most new features are not supported). Support for aioredis ==================== @@ -452,6 +452,15 @@ Revision history ================ +1.7.0 +----- +- Change a number of corner-case behaviours to match Redis 6.2.6. +- `#310 <https://github.com/jamesls/fakeredis/pull/310>`_ Fix DeprecationWarning for sampling from a set +- `#315 <https://github.com/jamesls/fakeredis/pull/315>`_ Improved support for constructor arguments +- `#316 <https://github.com/jamesls/fakeredis/pull/316>`_ Support redis-py 4 +- `#319 <https://github.com/jamesls/fakeredis/pull/319>`_ Add support for GET option to SET +- `#323 <https://github.com/jamesls/fakeredis/pull/323>`_ PERSIST and EXPIRE should invalidate watches + 1.6.1 ----- - `#305 <https://github.com/jamesls/fakeredis/pull/305>`_ Some packaging modernisation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/fakeredis/__init__.py new/fakeredis-1.7.0/fakeredis/__init__.py --- old/fakeredis-1.6.1/fakeredis/__init__.py 2021-09-06 11:00:58.000000000 +0200 +++ new/fakeredis-1.7.0/fakeredis/__init__.py 2021-11-23 07:07:12.000000000 +0100 @@ -1,4 +1,4 @@ from ._server import FakeServer, FakeRedis, FakeStrictRedis, FakeConnection # noqa: F401 -__version__ = '1.6.1' +__version__ = '1.7.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/fakeredis/_server.py new/fakeredis-1.7.0/fakeredis/_server.py --- old/fakeredis-1.6.1/fakeredis/_server.py 2021-09-06 11:00:58.000000000 +0200 +++ new/fakeredis-1.7.0/fakeredis/_server.py 2021-11-24 06:53:41.000000000 +0100 @@ -1,25 +1,25 @@ +import functools +import hashlib +import inspect +import itertools import logging -import time -import threading import math +import pickle +import queue import random import re +import threading +import time import warnings -import functools -import itertools -import hashlib import weakref -import queue -import pickle from collections import defaultdict from collections.abc import MutableMapping -import six import redis +import six from ._zset import ZSet - LOGGER = logging.getLogger('fakeredis') REDIS_LOG_LEVELS = { b'LOG_DEBUG': 0, @@ -86,6 +86,9 @@ FLAG_NO_SCRIPT = 's' # Command not allowed in scripts +# This needs to be grabbed early to avoid breaking tests that mock redis.Redis. +_ORIG_SIG = inspect.signature(redis.Redis) + class SimpleString: def __init__(self, value): @@ -240,6 +243,7 @@ def expireat(self, value): self._expireat = value self._expireat_modified = True + self._modified = True # Since redis 6.0.7 def get(self, default): return self._value if self else default @@ -1494,6 +1498,7 @@ xx = False nx = False keepttl = False + get = False while i < len(args): if casematch(args[i], b'nx'): nx = True @@ -1503,26 +1508,38 @@ i += 1 elif casematch(args[i], b'ex') and i + 1 < len(args): ex = Int.decode(args[i + 1]) - if ex <= 0: + if ex <= 0 or (self._db.time + ex) * 1000 >= 2**63: raise SimpleError(INVALID_EXPIRE_MSG.format('set')) i += 2 elif casematch(args[i], b'px') and i + 1 < len(args): px = Int.decode(args[i + 1]) - if px <= 0: + if px <= 0 or self._db.time * 1000 + px >= 2**63: raise SimpleError(INVALID_EXPIRE_MSG.format('set')) i += 2 elif casematch(args[i], b'keepttl'): keepttl = True i += 1 + elif casematch(args[i], b'get'): + get = True + i += 1 else: raise SimpleError(SYNTAX_ERROR_MSG) if (xx and nx) or ((px is not None) + (ex is not None) + keepttl > 1): raise SimpleError(SYNTAX_ERROR_MSG) + if nx and get: + # The command docs say this is allowed from Redis 7.0. + raise SimpleError(SYNTAX_ERROR_MSG) + + old_value = None + if get: + if key.value is not None and type(key.value) is not bytes: + raise SimpleError(WRONGTYPE_MSG) + old_value = key.value if nx and key: - return None + return old_value if xx and not key: - return None + return old_value if not keepttl: key.value = value else: @@ -1531,11 +1548,11 @@ key.expireat = self._db.time + ex if px is not None: key.expireat = self._db.time + px / 1000.0 - return OK + return OK if not get else old_value @command((Key(), Int, bytes)) def setex(self, key, seconds, value): - if seconds <= 0: + if seconds <= 0 or (self._db.time + seconds) * 1000 >= 2**63: raise SimpleError(INVALID_EXPIRE_MSG.format('setex')) key.value = value key.expireat = self._db.time + seconds @@ -1543,7 +1560,7 @@ @command((Key(), Int, bytes)) def psetex(self, key, ms, value): - if ms <= 0: + if ms <= 0 or self._db.time * 1000 + ms >= 2**63: raise SimpleError(INVALID_EXPIRE_MSG.format('psetex')) key.value = value key.expireat = self._db.time + ms / 1000.0 @@ -1754,14 +1771,38 @@ def llen(self, key): return len(key.value) - @command((Key(list),)) - def lpop(self, key): - try: - ret = key.value.pop(0) - key.updated() - return ret - except IndexError: + def _list_pop(self, get_slice, key, *args): + """Implements lpop and rpop. + + `get_slice` must take a count and return a slice expression for the + range to pop. + """ + # This implementation is somewhat contorted to match the odd + # behaviours described in https://github.com/redis/redis/issues/9680. + count = 1 + if len(args) > 1: + raise SimpleError(SYNTAX_ERROR_MSG) + elif len(args) == 1: + count = args[0] + if count < 0: + raise SimpleError(INDEX_ERROR_MSG) + elif count == 0: + return None + if not key: return None + elif type(key.value) != list: + raise SimpleError(WRONGTYPE_MSG) + slc = get_slice(count) + ret = key.value[slc] + del key.value[slc] + key.updated() + if not args: + ret = ret[0] + return ret + + @command((Key(),), (Int(),)) + def lpop(self, key, *args): + return self._list_pop(lambda count: slice(None, count), key, *args) @command((Key(list), bytes), (bytes,)) def lpush(self, key, *values): @@ -1826,14 +1867,9 @@ key.update(new_value) return OK - @command((Key(list),)) - def rpop(self, key): - try: - ret = key.value.pop() - key.updated() - return ret - except IndexError: - return None + @command((Key(),), (Int(),)) + def rpop(self, key, *args): + return self._list_pop(lambda count: slice(None, -count - 1, -1), key, *args) @command((Key(list, None), Key(list))) def rpoplpush(self, src, dst): @@ -1902,13 +1938,11 @@ def sdiffstore(self, dst, *keys): return self._setop(lambda a, b: a - b, False, dst, *keys) - # The following keys can't be marked as sets because of the - # stop_if_empty early-out. - @command((Key(set),), (Key(),)) + @command((Key(set),), (Key(set),)) def sinter(self, *keys): return self._setop(lambda a, b: a & b, True, None, *keys) - @command((Key(), Key(set)), (Key(),)) + @command((Key(), Key(set)), (Key(set),)) def sinterstore(self, dst, *keys): return self._setop(lambda a, b: a & b, True, dst, *keys) @@ -1937,7 +1971,7 @@ if count is None: if not key.value: return None - item = random.sample(key.value, 1)[0] + item = random.sample(list(key.value), 1)[0] key.value.remove(item) key.updated() return item @@ -1956,10 +1990,10 @@ if not key.value: return None else: - return random.sample(key.value, 1)[0] + return random.sample(list(key.value), 1)[0] elif count >= 0: count = min(count, len(key.value)) - return random.sample(key.value, count) + return random.sample(list(key.value), count) else: items = list(key.value) return [random.choice(items) for _ in range(-count)] @@ -2131,14 +2165,17 @@ def _zrange(self, key, start, stop, reverse, *args): zset = key.value - # TODO: does redis allow multiple WITHSCORES? - if len(args) > 1 or (args and not casematch(args[0], b'withscores')): - raise SimpleError(SYNTAX_ERROR_MSG) + withscores = False + for arg in args: + if casematch(arg, b'withscores'): + withscores = True + else: + raise SimpleError(SYNTAX_ERROR_MSG) start, stop = self._fix_range(start, stop, len(zset)) if reverse: start, stop = len(zset) - stop, len(zset) - start items = zset.islice_score(start, stop, reverse) - items = self._apply_withscores(items, bool(args)) + items = self._apply_withscores(items, withscores) return items @command((Key(ZSet), Int, Int), (bytes,)) @@ -2355,8 +2392,10 @@ # Server commands # TODO: lots - @command((), flags='s') - def bgsave(self): + @command((), (bytes,), flags='s') + def bgsave(self, *args): + if len(args) > 1 or (len(args) == 1 and not casematch(args[0], b'schedule')): + raise SimpleError(SYNTAX_ERROR_MSG) self._server.lastsave = int(time.time()) return BGSAVE_STARTED @@ -2493,7 +2532,7 @@ @command((bytes, Int), (bytes,), flags='s') def eval(self, script, numkeys, *keys_and_args): - from lupa import LuaRuntime, LuaError, as_attrgetter + from lupa import LuaError, LuaRuntime, as_attrgetter if numkeys > len(keys_and_args): raise SimpleError(TOO_MANY_KEYS_MSG) @@ -2560,7 +2599,7 @@ elif casematch(subcmd, b'exists'): return [int(sha1 in self._server.script_cache) for sha1 in args] elif casematch(subcmd, b'flush'): - if len(args) != 0: + if len(args) > 1 or (len(args) == 1 and casenorm(args[0]) not in {b'sync', b'async'}): raise SimpleError(BAD_SUBCOMMAND_MSG.format('SCRIPT')) self._server.script_cache = {} return OK @@ -2741,73 +2780,63 @@ class FakeRedisMixin: - def __init__(self, host='localhost', port=6379, - db=0, password=None, socket_timeout=None, - socket_connect_timeout=None, - socket_keepalive=None, socket_keepalive_options=None, - connection_pool=None, unix_socket_path=None, - encoding='utf-8', encoding_errors='strict', - charset=None, errors=None, - decode_responses=False, retry_on_timeout=False, - ssl=False, ssl_keyfile=None, ssl_certfile=None, - ssl_cert_reqs=None, ssl_ca_certs=None, - max_connections=None, server=None, - connected=True): - if not connection_pool: + def __init__(self, *args, server=None, connected=True, **kwargs): + # Interpret the positional and keyword arguments according to the + # version of redis in use. + bound = _ORIG_SIG.bind(*args, **kwargs) + bound.apply_defaults() + if not bound.arguments['connection_pool']: + charset = bound.arguments['charset'] + errors = bound.arguments['errors'] # Adapted from redis-py if charset is not None: warnings.warn(DeprecationWarning( '"charset" is deprecated. Use "encoding" instead')) - encoding = charset + bound.arguments['encoding'] = charset if errors is not None: warnings.warn(DeprecationWarning( '"errors" is deprecated. Use "encoding_errors" instead')) - encoding_errors = errors + bound.arguments['encoding_errors'] = errors if server is None: server = FakeServer() server.connected = connected kwargs = { - 'db': db, - 'password': password, - 'encoding': encoding, - 'encoding_errors': encoding_errors, - 'decode_responses': decode_responses, - 'max_connections': max_connections, 'connection_class': FakeConnection, 'server': server } - connection_pool = redis.connection.ConnectionPool(**kwargs) - # These need to be passed by name due to - # https://github.com/andymccurdy/redis-py/issues/1276 - super().__init__( - host=host, port=port, db=db, password=password, socket_timeout=socket_timeout, - socket_connect_timeout=socket_connect_timeout, - socket_keepalive=socket_keepalive, - socket_keepalive_options=socket_keepalive_options, - connection_pool=connection_pool, - unix_socket_path=unix_socket_path, - encoding=encoding, encoding_errors=encoding_errors, - charset=charset, errors=errors, - decode_responses=decode_responses, retry_on_timeout=retry_on_timeout, - ssl=ssl, ssl_keyfile=ssl_keyfile, ssl_certfile=ssl_certfile, - ssl_cert_reqs=ssl_cert_reqs, ssl_ca_certs=ssl_ca_certs, - max_connections=max_connections) + conn_pool_args = [ + 'db', + 'username', + 'password', + 'socket_timeout', + 'encoding', + 'encoding_errors', + 'decode_responses', + 'retry_on_timeout', + 'max_connections', + 'health_check_interval', + 'client_name' + ] + for arg in conn_pool_args: + if arg in bound.arguments: + kwargs[arg] = bound.arguments[arg] + bound.arguments['connection_pool'] = redis.connection.ConnectionPool(**kwargs) + super().__init__(*bound.args, **bound.kwargs) @classmethod - def from_url(cls, url, db=None, **kwargs): + def from_url(cls, *args, **kwargs): server = kwargs.pop('server', None) if server is None: server = FakeServer() - self = super().from_url(url, db, **kwargs) + pool = redis.ConnectionPool.from_url(*args, **kwargs) # Now override how it creates connections - pool = self.connection_pool pool.connection_class = FakeConnection pool.connection_kwargs['server'] = server # FakeConnection cannot handle the path kwarg (present when from_url # is called with a unix socket) pool.connection_kwargs.pop('path', None) - return self + return cls(connection_pool=pool) class FakeStrictRedis(FakeRedisMixin, redis.StrictRedis): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/fakeredis.egg-info/PKG-INFO new/fakeredis-1.7.0/fakeredis.egg-info/PKG-INFO --- old/fakeredis-1.6.1/fakeredis.egg-info/PKG-INFO 2021-09-08 17:25:37.000000000 +0200 +++ new/fakeredis-1.7.0/fakeredis.egg-info/PKG-INFO 2021-11-28 11:39:31.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fakeredis -Version: 1.6.1 +Version: 1.7.0 Summary: Fake implementation of redis API for testing purposes. Home-page: https://github.com/jamesls/fakeredis Author: James Saryerwinnie @@ -119,7 +119,7 @@ Fakeredis implements the same interface as `redis-py`_, the popular redis client for python, and models the responses -of redis 6.0 (although most new feature in 6.0 are not supported). +of redis 6.2 (although most new features are not supported). Support for aioredis ==================== @@ -476,6 +476,15 @@ Revision history ================ +1.7.0 +----- +- Change a number of corner-case behaviours to match Redis 6.2.6. +- `#310 <https://github.com/jamesls/fakeredis/pull/310>`_ Fix DeprecationWarning for sampling from a set +- `#315 <https://github.com/jamesls/fakeredis/pull/315>`_ Improved support for constructor arguments +- `#316 <https://github.com/jamesls/fakeredis/pull/316>`_ Support redis-py 4 +- `#319 <https://github.com/jamesls/fakeredis/pull/319>`_ Add support for GET option to SET +- `#323 <https://github.com/jamesls/fakeredis/pull/323>`_ PERSIST and EXPIRE should invalidate watches + 1.6.1 ----- - `#305 <https://github.com/jamesls/fakeredis/pull/305>`_ Some packaging modernisation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/fakeredis.egg-info/requires.txt new/fakeredis-1.7.0/fakeredis.egg-info/requires.txt --- old/fakeredis-1.6.1/fakeredis.egg-info/requires.txt 2021-09-08 17:25:37.000000000 +0200 +++ new/fakeredis-1.7.0/fakeredis.egg-info/requires.txt 2021-11-28 11:39:31.000000000 +0100 @@ -1,5 +1,5 @@ packaging -redis<3.6.0 +redis<4.1.0 six>=1.12 sortedcontainers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/requirements.in new/fakeredis-1.7.0/requirements.in --- old/fakeredis-1.6.1/requirements.in 2021-09-08 17:19:01.000000000 +0200 +++ new/fakeredis-1.7.0/requirements.in 2021-11-23 07:07:12.000000000 +0100 @@ -7,7 +7,7 @@ pytest-asyncio pytest-cov pytest-mock -redis==3.5.3 # Latest at time of writing +redis==4.0.0 # Latest at time of writing six sortedcontainers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/requirements.txt new/fakeredis-1.7.0/requirements.txt --- old/fakeredis-1.6.1/requirements.txt 2021-09-08 17:19:01.000000000 +0200 +++ new/fakeredis-1.7.0/requirements.txt 2021-11-23 07:07:12.000000000 +0100 @@ -16,6 +16,8 @@ # via # -r requirements.in # pytest-cov +deprecated==1.2.13 + # via redis flake8==3.8.4 # via -r requirements.in hiredis==1.1.0 @@ -24,7 +26,7 @@ # via -r requirements.in iniconfig==1.1.1 # via pytest -lupa==1.9 +lupa==1.10 # via -r requirements.in mccabe==0.6.1 # via flake8 @@ -40,7 +42,7 @@ # via flake8 pyparsing==2.4.7 # via packaging -pytest==6.1.2 +pytest==6.2.5 # via # -r requirements.in # pytest-asyncio @@ -52,7 +54,7 @@ # via -r requirements.in pytest-mock==3.3.1 # via -r requirements.in -redis==3.5.3 +redis==4.0.0 # via -r requirements.in six==1.15.0 # via -r requirements.in @@ -62,5 +64,7 @@ # hypothesis toml==0.10.2 # via pytest +wrapt==1.13.3 + # via deprecated zipp==1.2.0 # via -r requirements.in diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/setup.cfg new/fakeredis-1.7.0/setup.cfg --- old/fakeredis-1.6.1/setup.cfg 2021-09-08 17:25:37.496013600 +0200 +++ new/fakeredis-1.7.0/setup.cfg 2021-11-28 11:39:31.071334000 +0100 @@ -23,7 +23,7 @@ packages = fakeredis install_requires = packaging - redis<3.6.0 + redis<4.1.0 six>=1.12 sortedcontainers python_requires = >=3.5 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/test/test_fakeredis.py new/fakeredis-1.7.0/test/test_fakeredis.py --- old/fakeredis-1.6.1/test/test_fakeredis.py 2021-09-06 11:00:58.000000000 +0200 +++ new/fakeredis-1.7.0/test/test_fakeredis.py 2021-11-24 06:53:41.000000000 +0100 @@ -709,6 +709,12 @@ r.setex('foo', 1.2, 'bar') +@pytest.mark.min_server('6.2') +def test_setex_overflow(r): + with pytest.raises(ResponseError): + r.setex('foo', 18446744073709561, 'bar') # Overflows long long in ms + + def test_set_ex(r): assert r.set('foo', 'bar', ex=100) is True assert r.get('foo') == b'bar' @@ -719,6 +725,16 @@ assert r.get('foo') == b'bar' +def test_set_ex_overflow(r): + with pytest.raises(ResponseError): + r.set('foo', 'bar', ex=18446744073709561) # Overflows long long in ms + + +def test_set_px_overflow(r): + with pytest.raises(ResponseError): + r.set('foo', 'bar', px=2**63 - 2) # Overflows after adding current time + + def test_set_px(r): assert r.set('foo', 'bar', px=100) is True assert r.get('foo') == b'bar' @@ -821,6 +837,38 @@ assert r.set('foo', 'bar', xx=True) is True +@pytest.mark.min_server('6.2') +def test_set_get(r): + assert raw_command(r, 'set', 'foo', 'bar', 'GET') is None + assert r.get('foo') == b'bar' + assert raw_command(r, 'set', 'foo', 'baz', 'GET') == b'bar' + assert r.get('foo') == b'baz' + + +@pytest.mark.min_server('6.2') +def test_set_get_xx(r): + assert raw_command(r, 'set', 'foo', 'bar', 'XX', 'GET') is None + assert r.get('foo') is None + r.set('foo', 'bar') + assert raw_command(r, 'set', 'foo', 'baz', 'XX', 'GET') == b'bar' + assert r.get('foo') == b'baz' + assert raw_command(r, 'set', 'foo', 'baz', 'GET') == b'baz' + + +@pytest.mark.min_server('6.2') +def test_set_get_nx(r): + # Note: this will most likely fail on a 7.0 server, based on the docs for SET + with pytest.raises(redis.ResponseError): + raw_command(r, 'set', 'foo', 'bar', 'NX', 'GET') + + +@pytest.mark.min_server('6.2') +def set_get_wrongtype(r): + r.lpush('foo', 'bar') + with pytest.raises(redis.ResponseError): + raw_command(r, 'set', 'foo', 'bar', 'GET') + + def test_del_operator(r): r['foo'] = 'bar' del r['foo'] @@ -1041,6 +1089,22 @@ r.lpop('foo') +@pytest.mark.min_server('6.2') +def test_lpop_count(r): + assert r.rpush('foo', 'one') == 1 + assert r.rpush('foo', 'two') == 2 + assert r.rpush('foo', 'three') == 3 + assert raw_command(r, 'lpop', 'foo', 2) == [b'one', b'two'] + # See https://github.com/redis/redis/issues/9680 + assert raw_command(r, 'lpop', 'foo', 0) is None + + +@pytest.mark.min_server('6.2') +def test_lpop_count_negative(r): + with pytest.raises(redis.ResponseError): + raw_command(r, 'lpop', 'foo', -1) + + def test_lset(r): r.rpush('foo', 'one') r.rpush('foo', 'two') @@ -1148,6 +1212,22 @@ r.rpop('foo') +@pytest.mark.min_server('6.2') +def test_rpop_count(r): + assert r.rpush('foo', 'one') == 1 + assert r.rpush('foo', 'two') == 2 + assert r.rpush('foo', 'three') == 3 + assert raw_command(r, 'rpop', 'foo', 2) == [b'three', b'two'] + # See https://github.com/redis/redis/issues/9680 + assert raw_command(r, 'rpop', 'foo', 0) is None + + +@pytest.mark.min_server('6.2') +def test_rpop_count_negative(r): + with pytest.raises(redis.ResponseError): + raw_command(r, 'rpop', 'foo', -1) + + def test_linsert_before(r): r.rpush('foo', 'hello') r.rpush('foo', 'world') @@ -3454,6 +3534,10 @@ def test_bgsave(r): assert r.bgsave() + with pytest.raises(ResponseError): + r.execute_command('BGSAVE', 'SCHEDULE', 'FOO') + with pytest.raises(ResponseError): + r.execute_command('BGSAVE', 'FOO') def test_lastsave(r): @@ -4052,6 +4136,18 @@ assert r.expire('bar', 1) is False +def test_watch_expire(r): + """EXPIRE should mark a key as changed for WATCH.""" + r.set('foo', 'bar') + with r.pipeline() as p: + p.watch('foo') + r.expire('foo', 10000) + p.multi() + p.get('foo') + with pytest.raises(redis.exceptions.WatchError): + p.execute() + + @pytest.mark.slow def test_pexpire_should_expire_key(r): r.set('foo', 'bar') @@ -4179,6 +4275,18 @@ assert r.persist('foo') == 0 +def test_watch_persist(r): + """PERSIST should mark a variable as changed.""" + r.set('foo', 'bar', ex=10000) + with r.pipeline() as p: + p.watch('foo') + r.persist('foo') + p.multi() + p.get('foo') + with pytest.raises(redis.exceptions.WatchError): + p.execute() + + def test_set_existing_key_persists(r): r.set('foo', 'bar', ex=20) r.set('foo', 'foo') @@ -5004,10 +5112,10 @@ assert db2.get('foo') == b'foo2' def test_from_url_db_value_error(self): - # In ValueError, should default to 0 + # In case of ValueError, should default to 0, or be absent in redis-py 4.0 db = fakeredis.FakeStrictRedis.from_url( 'redis://localhost:6379/a') - assert db.connection_pool.connection_kwargs['db'] == 0 + assert db.connection_pool.connection_kwargs.get('db', 0) == 0 def test_can_pass_through_extra_args(self): db = fakeredis.FakeStrictRedis.from_url( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fakeredis-1.6.1/test/test_hypothesis.py new/fakeredis-1.7.0/test/test_hypothesis.py --- old/fakeredis-1.6.1/test/test_hypothesis.py 2021-03-23 09:27:16.000000000 +0100 +++ new/fakeredis-1.7.0/test/test_hypothesis.py 2021-11-23 07:07:12.000000000 +0100 @@ -204,7 +204,10 @@ | commands(st.just('mget'), st.lists(keys)) | commands(st.sampled_from(['mset', 'msetnx']), st.lists(st.tuples(keys, values))) | commands(st.just('set'), keys, values, - st.none() | st.just('nx'), st.none() | st.just('xx')) + st.none() | st.just('nx'), + st.none() | st.just('xx'), + st.none() | st.just('keepttl'), + st.none() | st.just('get')) | commands(st.just('setex'), keys, expires_seconds, values) | commands(st.just('psetex'), keys, expires_ms, values) | commands(st.just('setnx'), keys, values) @@ -239,7 +242,7 @@ st.sampled_from(['before', 'after', 'BEFORE', 'AFTER']) | st.binary(), values, values) | commands(st.just('llen'), keys) - | commands(st.sampled_from(['lpop', 'rpop']), keys) + | commands(st.sampled_from(['lpop', 'rpop']), keys, st.just(None) | st.integers()) | commands(st.sampled_from(['lpush', 'lpushx', 'rpush', 'rpushx']), keys, st.lists(values)) | commands(st.just('lrange'), keys, counts, counts) | commands(st.just('lrem'), keys, counts, values)