From 9b33349c2474627b9dee86ba8e34678e103a3cc2 Mon Sep 17 00:00:00 2001 From: AvitalFineRedis Date: Wed, 21 Jul 2021 15:45:06 +0300 Subject: [PATCH 1/3] getex --- redis/client.py | 48 ++++++++++++++++++++++++++++++++++++++++++ tests/test_commands.py | 15 +++++++++++++ 2 files changed, 63 insertions(+) diff --git a/redis/client.py b/redis/client.py index 72178f3068..3f8421ddef 100755 --- a/redis/client.py +++ b/redis/client.py @@ -1689,6 +1689,54 @@ def get(self, name): """ return self.execute_command('GET', name) + def getex(self, name, + ex=None, px=None, exat=None, pxat=None, persist=False): + """ + Get the value of key and optionally set its expiration. + GETEX is similar to GET, but is a write command with + additional options. + + ``ex`` Set the specified expire time, in seconds. + + ``px`` Set the specified expire time, in milliseconds. + + ``exat`` Set the specified Unix time at which the key + will expire, in seconds. + + ``pxat`` Set the specified Unix time at which the key + will expire, in milliseconds. + + ``persist`` Remove the time to live associated with the key. + """ + + pieces = [] + if ex is not None: + pieces.append('EX') + if isinstance(ex, datetime.timedelta): + ex = int(ex.total_seconds()) + pieces.append(ex) + if px is not None: + pieces.append('PX') + if isinstance(px, datetime.timedelta): + px = int(px.total_seconds() * 1000) + pieces.append(px) + if exat is not None: + pieces.append('EXAT') + if isinstance(exat, datetime.datetime): + s = int(exat.microsecond / 1000000) + exat = int(mod_time.mktime(exat.timetuple())) + s + pieces.append(exat) + if pxat is not None: + pieces.append('PXAT') + if isinstance(pxat, datetime.datetime): + ms = int(pxat.microsecond / 1000) + pxat = int(mod_time.mktime(pxat.timetuple())) * 1000 + ms + pieces.append(pxat) + if persist: + pieces.append('PERSIST') + + return self.execute_command('GETEX', name, *pieces) + def __getitem__(self, name): """ Return the value at key ``name``, raises a KeyError if the key diff --git a/tests/test_commands.py b/tests/test_commands.py index a5a7e45e2f..eafd2c7e74 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -727,6 +727,21 @@ def test_get_and_set(self, r): assert r.get('integer') == str(integer).encode() assert r.get('unicode_string').decode('utf-8') == unicode_string + @skip_if_server_version_lt('6.2.0') + def test_getex(self, r): + assert r.set('a', 1) + assert r.getex('a') == b'1' + assert r.ttl('a') == -1 + assert r.getex('a', ex=60) == b'1' + assert r.ttl('a') == 60 + assert r.getex('a', px=6000) == b'1' + assert r.ttl('a') == 6 + expire_at = redis_server_time(r) + datetime.timedelta(minutes=1) + assert r.getex('a', pxat=expire_at) == b'1' + assert r.ttl('a') <= 60 + assert r.getex('a', persist=True) == b'1' + assert r.ttl('a') == -1 + def test_getitem_and_setitem(self, r): r['a'] = 'bar' assert r['a'] == b'bar' From 1eebecdfaf97d8b6647ce51e3b8b1a5daafe4346 Mon Sep 17 00:00:00 2001 From: AvitalFineRedis Date: Wed, 21 Jul 2021 16:18:30 +0300 Subject: [PATCH 2/3] flake8 fix --- redis/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redis/client.py b/redis/client.py index 3f8421ddef..0bcccbab44 100755 --- a/redis/client.py +++ b/redis/client.py @@ -1690,7 +1690,7 @@ def get(self, name): return self.execute_command('GET', name) def getex(self, name, - ex=None, px=None, exat=None, pxat=None, persist=False): + ex=None, px=None, exat=None, pxat=None, persist=False): """ Get the value of key and optionally set its expiration. GETEX is similar to GET, but is a write command with From 2dc3a8a667bc34d7eedfc6600473fda9e5f0f3db Mon Sep 17 00:00:00 2001 From: AvitalFineRedis Date: Thu, 22 Jul 2021 10:47:56 +0300 Subject: [PATCH 3/3] comments --- redis/client.py | 19 +++++++++++-------- tests/test_commands.py | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/redis/client.py b/redis/client.py index 0bcccbab44..8b1b35392c 100755 --- a/redis/client.py +++ b/redis/client.py @@ -1694,22 +1694,24 @@ def getex(self, name, """ Get the value of key and optionally set its expiration. GETEX is similar to GET, but is a write command with - additional options. + additional options. All time parameters can be given as + datetime.timedelta or integers. - ``ex`` Set the specified expire time, in seconds. + ``ex`` sets an expire flag on key ``name`` for ``ex`` seconds. - ``px`` Set the specified expire time, in milliseconds. + ``px`` sets an expire flag on key ``name`` for ``px`` milliseconds. - ``exat`` Set the specified Unix time at which the key - will expire, in seconds. + ``exat`` sets an expire flag on key ``name`` for ``ex`` seconds, + specified in unix time. - ``pxat`` Set the specified Unix time at which the key - will expire, in milliseconds. + ``pxat`` sets an expire flag on key ``name`` for ``ex`` milliseconds, + specified in unix time. - ``persist`` Remove the time to live associated with the key. + ``persist`` remove the time to live associated with ``name``. """ pieces = [] + # similar to set command if ex is not None: pieces.append('EX') if isinstance(ex, datetime.timedelta): @@ -1720,6 +1722,7 @@ def getex(self, name, if isinstance(px, datetime.timedelta): px = int(px.total_seconds() * 1000) pieces.append(px) + # similar to pexpireat command if exat is not None: pieces.append('EXAT') if isinstance(exat, datetime.datetime): diff --git a/tests/test_commands.py b/tests/test_commands.py index eafd2c7e74..088404a23c 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -729,7 +729,7 @@ def test_get_and_set(self, r): @skip_if_server_version_lt('6.2.0') def test_getex(self, r): - assert r.set('a', 1) + r.set('a', 1) assert r.getex('a') == b'1' assert r.ttl('a') == -1 assert r.getex('a', ex=60) == b'1'