44
44
TimeoutSecT ,
45
45
ZScoreBoundT ,
46
46
)
47
+ from redis .utils import (
48
+ deprecated_function ,
49
+ extract_expire_flags ,
50
+ )
47
51
48
52
from .helpers import list_or_args
49
53
@@ -1837,10 +1841,10 @@ def getdel(self, name: KeyT) -> ResponseT:
1837
1841
def getex (
1838
1842
self ,
1839
1843
name : KeyT ,
1840
- ex : Union [ExpiryT , None ] = None ,
1841
- px : Union [ExpiryT , None ] = None ,
1842
- exat : Union [AbsExpiryT , None ] = None ,
1843
- pxat : Union [AbsExpiryT , None ] = None ,
1844
+ ex : Optional [ExpiryT ] = None ,
1845
+ px : Optional [ExpiryT ] = None ,
1846
+ exat : Optional [AbsExpiryT ] = None ,
1847
+ pxat : Optional [AbsExpiryT ] = None ,
1844
1848
persist : bool = False ,
1845
1849
) -> ResponseT :
1846
1850
"""
@@ -1863,41 +1867,19 @@ def getex(
1863
1867
1864
1868
For more information see https://redis.io/commands/getex
1865
1869
"""
1866
-
1867
1870
opset = {ex , px , exat , pxat }
1868
1871
if len (opset ) > 2 or len (opset ) > 1 and persist :
1869
1872
raise DataError (
1870
1873
"``ex``, ``px``, ``exat``, ``pxat``, "
1871
1874
"and ``persist`` are mutually exclusive."
1872
1875
)
1873
1876
1874
- pieces : list [EncodableT ] = []
1875
- # similar to set command
1876
- if ex is not None :
1877
- pieces .append ("EX" )
1878
- if isinstance (ex , datetime .timedelta ):
1879
- ex = int (ex .total_seconds ())
1880
- pieces .append (ex )
1881
- if px is not None :
1882
- pieces .append ("PX" )
1883
- if isinstance (px , datetime .timedelta ):
1884
- px = int (px .total_seconds () * 1000 )
1885
- pieces .append (px )
1886
- # similar to pexpireat command
1887
- if exat is not None :
1888
- pieces .append ("EXAT" )
1889
- if isinstance (exat , datetime .datetime ):
1890
- exat = int (exat .timestamp ())
1891
- pieces .append (exat )
1892
- if pxat is not None :
1893
- pieces .append ("PXAT" )
1894
- if isinstance (pxat , datetime .datetime ):
1895
- pxat = int (pxat .timestamp () * 1000 )
1896
- pieces .append (pxat )
1877
+ exp_options : list [EncodableT ] = extract_expire_flags (ex , px , exat , pxat )
1878
+
1897
1879
if persist :
1898
- pieces .append ("PERSIST" )
1880
+ exp_options .append ("PERSIST" )
1899
1881
1900
- return self .execute_command ("GETEX" , name , * pieces )
1882
+ return self .execute_command ("GETEX" , name , * exp_options )
1901
1883
1902
1884
def __getitem__ (self , name : KeyT ):
1903
1885
"""
@@ -2255,14 +2237,14 @@ def set(
2255
2237
self ,
2256
2238
name : KeyT ,
2257
2239
value : EncodableT ,
2258
- ex : Union [ExpiryT , None ] = None ,
2259
- px : Union [ExpiryT , None ] = None ,
2240
+ ex : Optional [ExpiryT ] = None ,
2241
+ px : Optional [ExpiryT ] = None ,
2260
2242
nx : bool = False ,
2261
2243
xx : bool = False ,
2262
2244
keepttl : bool = False ,
2263
2245
get : bool = False ,
2264
- exat : Union [AbsExpiryT , None ] = None ,
2265
- pxat : Union [AbsExpiryT , None ] = None ,
2246
+ exat : Optional [AbsExpiryT ] = None ,
2247
+ pxat : Optional [AbsExpiryT ] = None ,
2266
2248
) -> ResponseT :
2267
2249
"""
2268
2250
Set the value at key ``name`` to ``value``
@@ -2292,36 +2274,21 @@ def set(
2292
2274
2293
2275
For more information see https://redis.io/commands/set
2294
2276
"""
2277
+ opset = {ex , px , exat , pxat }
2278
+ if len (opset ) > 2 or len (opset ) > 1 and keepttl :
2279
+ raise DataError (
2280
+ "``ex``, ``px``, ``exat``, ``pxat``, "
2281
+ "and ``keepttl`` are mutually exclusive."
2282
+ )
2283
+
2284
+ if nx and xx :
2285
+ raise DataError ("``nx`` and ``xx`` are mutually exclusive." )
2286
+
2295
2287
pieces : list [EncodableT ] = [name , value ]
2296
2288
options = {}
2297
- if ex is not None :
2298
- pieces .append ("EX" )
2299
- if isinstance (ex , datetime .timedelta ):
2300
- pieces .append (int (ex .total_seconds ()))
2301
- elif isinstance (ex , int ):
2302
- pieces .append (ex )
2303
- elif isinstance (ex , str ) and ex .isdigit ():
2304
- pieces .append (int (ex ))
2305
- else :
2306
- raise DataError ("ex must be datetime.timedelta or int" )
2307
- if px is not None :
2308
- pieces .append ("PX" )
2309
- if isinstance (px , datetime .timedelta ):
2310
- pieces .append (int (px .total_seconds () * 1000 ))
2311
- elif isinstance (px , int ):
2312
- pieces .append (px )
2313
- else :
2314
- raise DataError ("px must be datetime.timedelta or int" )
2315
- if exat is not None :
2316
- pieces .append ("EXAT" )
2317
- if isinstance (exat , datetime .datetime ):
2318
- exat = int (exat .timestamp ())
2319
- pieces .append (exat )
2320
- if pxat is not None :
2321
- pieces .append ("PXAT" )
2322
- if isinstance (pxat , datetime .datetime ):
2323
- pxat = int (pxat .timestamp () * 1000 )
2324
- pieces .append (pxat )
2289
+
2290
+ pieces .extend (extract_expire_flags (ex , px , exat , pxat ))
2291
+
2325
2292
if keepttl :
2326
2293
pieces .append ("KEEPTTL" )
2327
2294
@@ -4980,6 +4947,65 @@ def hgetall(self, name: str) -> Union[Awaitable[dict], dict]:
4980
4947
"""
4981
4948
return self .execute_command ("HGETALL" , name , keys = [name ])
4982
4949
4950
+ def hgetdel (
4951
+ self , name : str , * keys : str
4952
+ ) -> Union [Awaitable [Optional [str ]], Optional [str ]]:
4953
+ """
4954
+ Return the value of ``key`` within the hash ``name`` and
4955
+ delete the field in the hash.
4956
+ This command is similar to HGET, except for the fact that it also deletes
4957
+ the key on success from the hash with the provided ```name```.
4958
+
4959
+ Available since Redis 8.0
4960
+ For more information see https://redis.io/commands/hgetdel
4961
+ """
4962
+ return self .execute_command ("HGETDEL" , name , "FIELDS" , len (keys ), * keys )
4963
+
4964
+ def hgetex (
4965
+ self ,
4966
+ name : KeyT ,
4967
+ * keys : str ,
4968
+ ex : Optional [ExpiryT ] = None ,
4969
+ px : Optional [ExpiryT ] = None ,
4970
+ exat : Optional [AbsExpiryT ] = None ,
4971
+ pxat : Optional [AbsExpiryT ] = None ,
4972
+ persist : bool = False ,
4973
+ ) -> Union [Awaitable [Optional [str ]], Optional [str ]]:
4974
+ """
4975
+ Return the values of ``keys`` within the hash ``name``
4976
+ and optionally set their expiration.
4977
+
4978
+ ``ex`` sets an expire flag on ``kyes`` for ``ex`` seconds.
4979
+
4980
+ ``px`` sets an expire flag on ``keys`` for ``px`` milliseconds.
4981
+
4982
+ ``exat`` sets an expire flag on ``keys`` for ``ex`` seconds,
4983
+ specified in unix time.
4984
+
4985
+ ``pxat`` sets an expire flag on ``keys`` for ``ex`` milliseconds,
4986
+ specified in unix time.
4987
+
4988
+ ``persist`` remove the time to live associated with the ``keys``.
4989
+
4990
+ Available since Redis 8.0
4991
+ For more information see https://redis.io/commands/hgetex
4992
+ """
4993
+ opset = {ex , px , exat , pxat }
4994
+ if len (opset ) > 2 or len (opset ) > 1 and persist :
4995
+ raise DataError (
4996
+ "``ex``, ``px``, ``exat``, ``pxat``, "
4997
+ "and ``persist`` are mutually exclusive."
4998
+ )
4999
+
5000
+ exp_options : list [EncodableT ] = extract_expire_flags (ex , px , exat , pxat )
5001
+
5002
+ if persist :
5003
+ exp_options .append ("PERSIST" )
5004
+
5005
+ return self .execute_command (
5006
+ "HGETEX" , name , * exp_options , "FIELDS" , len (keys ), * keys
5007
+ )
5008
+
4983
5009
def hincrby (
4984
5010
self , name : str , key : str , amount : int = 1
4985
5011
) -> Union [Awaitable [int ], int ]:
@@ -5047,6 +5073,87 @@ def hset(
5047
5073
5048
5074
return self .execute_command ("HSET" , name , * pieces )
5049
5075
5076
+ def hsetex (
5077
+ self ,
5078
+ name : str ,
5079
+ key : Optional [str ] = None ,
5080
+ value : Optional [str ] = None ,
5081
+ mapping : Optional [dict ] = None ,
5082
+ items : Optional [list ] = None ,
5083
+ ex : Optional [ExpiryT ] = None ,
5084
+ px : Optional [ExpiryT ] = None ,
5085
+ exat : Optional [AbsExpiryT ] = None ,
5086
+ pxat : Optional [AbsExpiryT ] = None ,
5087
+ fnx : bool = False ,
5088
+ fxx : bool = False ,
5089
+ keepttl : bool = False ,
5090
+ ) -> Union [Awaitable [int ], int ]:
5091
+ """
5092
+ Set ``key`` to ``value`` within hash ``name``
5093
+
5094
+ ``mapping`` accepts a dict of key/value pairs that will be
5095
+ added to hash ``name``.
5096
+
5097
+ ``items`` accepts a list of key/value pairs that will be
5098
+ added to hash ``name``.
5099
+
5100
+ ``ex`` sets an expire flag on ``keys`` for ``ex`` seconds.
5101
+
5102
+ ``px`` sets an expire flag on ``keys`` for ``px`` milliseconds.
5103
+
5104
+ ``exat`` sets an expire flag on ``keys`` for ``ex`` seconds,
5105
+ specified in unix time.
5106
+
5107
+ ``pxat`` sets an expire flag on ``keys`` for ``ex`` milliseconds,
5108
+ specified in unix time.
5109
+
5110
+ ``fnx`` if set to True, set the value for each provided key to each
5111
+ provided value only if all do not already exist.
5112
+
5113
+ ``fxx`` if set to True, set the value for each provided key to each
5114
+ provided value only if all already exist.
5115
+
5116
+ ``keepttl`` if True, retain the time to live associated with the keys.
5117
+
5118
+ Returns the number of fields that were added.
5119
+
5120
+ Available since Redis 8.0
5121
+ For more information see https://redis.io/commands/hsetex
5122
+ """
5123
+ if key is None and not mapping and not items :
5124
+ raise DataError ("'hsetex' with no key value pairs" )
5125
+
5126
+ opset = {ex , px , exat , pxat }
5127
+ if len (opset ) > 2 or len (opset ) > 1 and keepttl :
5128
+ raise DataError (
5129
+ "``ex``, ``px``, ``exat``, ``pxat``, "
5130
+ "and ``keepttl`` are mutually exclusive."
5131
+ )
5132
+
5133
+ if fnx and fxx :
5134
+ raise DataError ("``fnx`` and ``fxx`` are mutually exclusive." )
5135
+
5136
+ exp_options : list [EncodableT ] = extract_expire_flags (ex , px , exat , pxat )
5137
+ if fnx :
5138
+ exp_options .append ("FNX" )
5139
+ if fxx :
5140
+ exp_options .append ("FXX" )
5141
+ if keepttl :
5142
+ exp_options .append ("KEEPTTL" )
5143
+
5144
+ pieces = []
5145
+ if items :
5146
+ pieces .extend (items )
5147
+ if key is not None :
5148
+ pieces .extend ((key , value ))
5149
+ if mapping :
5150
+ for pair in mapping .items ():
5151
+ pieces .extend (pair )
5152
+
5153
+ return self .execute_command (
5154
+ "HSETEX" , name , * exp_options , "FIELDS" , int (len (pieces ) / 2 ), * pieces
5155
+ )
5156
+
5050
5157
def hsetnx (self , name : str , key : str , value : str ) -> Union [Awaitable [bool ], bool ]:
5051
5158
"""
5052
5159
Set ``key`` to ``value`` within hash ``name`` if ``key`` does not
@@ -5056,19 +5163,18 @@ def hsetnx(self, name: str, key: str, value: str) -> Union[Awaitable[bool], bool
5056
5163
"""
5057
5164
return self .execute_command ("HSETNX" , name , key , value )
5058
5165
5166
+ @deprecated_function (
5167
+ version = "4.0.0" ,
5168
+ reason = "Use 'hset' instead." ,
5169
+ name = "hmset" ,
5170
+ )
5059
5171
def hmset (self , name : str , mapping : dict ) -> Union [Awaitable [str ], str ]:
5060
5172
"""
5061
5173
Set key to value within hash ``name`` for each corresponding
5062
5174
key and value from the ``mapping`` dict.
5063
5175
5064
5176
For more information see https://redis.io/commands/hmset
5065
5177
"""
5066
- warnings .warn (
5067
- f"{ self .__class__ .__name__ } .hmset() is deprecated. "
5068
- f"Use { self .__class__ .__name__ } .hset() instead." ,
5069
- DeprecationWarning ,
5070
- stacklevel = 2 ,
5071
- )
5072
5178
if not mapping :
5073
5179
raise DataError ("'hmset' with 'mapping' of length 0" )
5074
5180
items = []
0 commit comments