5050 extract_expire_flags ,
5151)
5252
53- from .helpers import list_or_args
53+ from .helpers import at_most_one_value_set , list_or_args
5454
5555if TYPE_CHECKING :
5656 import redis .asyncio .client
@@ -1732,8 +1732,8 @@ def __delitem__(self, name: KeyT):
17321732 def delex (
17331733 self ,
17341734 name : KeyT ,
1735- ifeq : Optional [EncodableT ] = None ,
1736- ifne : Optional [EncodableT ] = None ,
1735+ ifeq : Optional [Union [ bytes , str ] ] = None ,
1736+ ifne : Optional [Union [ bytes , str ] ] = None ,
17371737 ifdeq : Optional [str ] = None , # hex digest
17381738 ifdne : Optional [str ] = None , # hex digest
17391739 ) -> int :
@@ -1752,6 +1752,8 @@ def delex(
17521752 and a condition is specified.
17531753 ValueError: if more than one condition is provided.
17541754
1755+
1756+ Requires Redis 8.4 or greater.
17551757 For more information, see https://redis.io/commands/delex
17561758 """
17571759 conds = [x is not None for x in (ifeq , ifne , ifdeq , ifdne )]
@@ -1886,6 +1888,8 @@ def digest(self, name: KeyT) -> Optional[str]:
18861888 Raises:
18871889 - ResponseError if key exists but is not a string
18881890
1891+
1892+ Requires Redis 8.4 or greater.
18891893 For more information, see https://redis.io/commands/digest
18901894 """
18911895 # Bulk string response is already handled (bytes/str based on decode_responses)
@@ -1939,8 +1943,7 @@ def getex(
19391943
19401944 For more information, see https://redis.io/commands/getex
19411945 """
1942- opset = {ex , px , exat , pxat }
1943- if len (opset ) > 2 or len (opset ) > 1 and persist :
1946+ if not at_most_one_value_set ((ex , px , exat , pxat , persist )):
19441947 raise DataError (
19451948 "``ex``, ``px``, ``exat``, ``pxat``, "
19461949 "and ``persist`` are mutually exclusive."
@@ -2128,8 +2131,7 @@ def msetex(
21282131 Available since Redis 8.4
21292132 For more information, see https://redis.io/commands/msetex
21302133 """
2131- opset = {ex , px , exat , pxat }
2132- if len (opset ) > 2 or len (opset ) > 1 and keepttl :
2134+ if not at_most_one_value_set ((ex , px , exat , pxat , keepttl )):
21332135 raise DataError (
21342136 "``ex``, ``px``, ``exat``, ``pxat``, "
21352137 "and ``keepttl`` are mutually exclusive."
@@ -2395,6 +2397,10 @@ def set(
23952397 get : bool = False ,
23962398 exat : Optional [AbsExpiryT ] = None ,
23972399 pxat : Optional [AbsExpiryT ] = None ,
2400+ ifeq : Optional [Union [bytes , str ]] = None ,
2401+ ifne : Optional [Union [bytes , str ]] = None ,
2402+ ifdeq : Optional [str ] = None , # hex digest of current value
2403+ ifdne : Optional [str ] = None , # hex digest of current value
23982404 ) -> ResponseT :
23992405 """
24002406 Set the value at key ``name`` to ``value``
@@ -2422,35 +2428,67 @@ def set(
24222428 ``pxat`` sets an expire flag on key ``name`` for ``ex`` milliseconds,
24232429 specified in unix time.
24242430
2431+ ``ifeq`` set the value at key ``name`` to ``value`` only if the current
2432+ value exactly matches the argument.
2433+ If key doesn’t exist - it won’t be created.
2434+ (Requires Redis 8.4 or greater)
2435+
2436+ ``ifne`` set the value at key ``name`` to ``value`` only if the current
2437+ value does not exactly match the argument.
2438+ If key doesn’t exist - it will be created.
2439+ (Requires Redis 8.4 or greater)
2440+
2441+ ``ifdeq`` set the value at key ``name`` to ``value`` only if the current
2442+ value XXH3 hex digest exactly matches the argument.
2443+ If key doesn’t exist - it won’t be created.
2444+ (Requires Redis 8.4 or greater)
2445+
2446+ ``ifdne`` set the value at key ``name`` to ``value`` only if the current
2447+ value XXH3 hex digest does not exactly match the argument.
2448+ If key doesn’t exist - it will be created.
2449+ (Requires Redis 8.4 or greater)
2450+
24252451 For more information, see https://redis.io/commands/set
24262452 """
2427- opset = { ex , px , exat , pxat }
2428- if len ( opset ) > 2 or len ( opset ) > 1 and keepttl :
2453+
2454+ if not at_most_one_value_set (( ex , px , exat , pxat , keepttl )) :
24292455 raise DataError (
24302456 "``ex``, ``px``, ``exat``, ``pxat``, "
24312457 "and ``keepttl`` are mutually exclusive."
24322458 )
24332459
2434- if nx and xx :
2435- raise DataError ("``nx`` and ``xx`` are mutually exclusive." )
2460+ # Enforce mutual exclusivity among all conditional switches.
2461+ if not at_most_one_value_set ((nx , xx , ifeq , ifne , ifdeq , ifdne )):
2462+ raise DataError (
2463+ "``nx``, ``xx``, ``ifeq``, ``ifne``, ``ifdeq``, ``ifdne`` are mutually exclusive."
2464+ )
24362465
24372466 pieces : list [EncodableT ] = [name , value ]
24382467 options = {}
24392468
2440- pieces .extend (extract_expire_flags (ex , px , exat , pxat ))
2441-
2442- if keepttl :
2443- pieces .append ("KEEPTTL" )
2444-
2469+ # Conditional modifier (exactly one at most)
24452470 if nx :
24462471 pieces .append ("NX" )
2447- if xx :
2472+ elif xx :
24482473 pieces .append ("XX" )
2474+ elif ifeq is not None :
2475+ pieces .extend (("IFEQ" , ifeq ))
2476+ elif ifne is not None :
2477+ pieces .extend (("IFNE" , ifne ))
2478+ elif ifdeq is not None :
2479+ pieces .extend (("IFDEQ" , ifdeq ))
2480+ elif ifdne is not None :
2481+ pieces .extend (("IFDNE" , ifdne ))
24492482
24502483 if get :
24512484 pieces .append ("GET" )
24522485 options ["get" ] = True
24532486
2487+ pieces .extend (extract_expire_flags (ex , px , exat , pxat ))
2488+
2489+ if keepttl :
2490+ pieces .append ("KEEPTTL" )
2491+
24542492 return self .execute_command ("SET" , * pieces , ** options )
24552493
24562494 def __setitem__ (self , name : KeyT , value : EncodableT ):
@@ -5257,8 +5295,7 @@ def hgetex(
52575295 if not keys :
52585296 raise DataError ("'hgetex' should have at least one key provided" )
52595297
5260- opset = {ex , px , exat , pxat }
5261- if len (opset ) > 2 or len (opset ) > 1 and persist :
5298+ if not at_most_one_value_set ((ex , px , exat , pxat , persist )):
52625299 raise DataError (
52635300 "``ex``, ``px``, ``exat``, ``pxat``, "
52645301 "and ``persist`` are mutually exclusive."
@@ -5403,8 +5440,7 @@ def hsetex(
54035440 "'items' must contain a list of key/value pairs."
54045441 )
54055442
5406- opset = {ex , px , exat , pxat }
5407- if len (opset ) > 2 or len (opset ) > 1 and keepttl :
5443+ if not at_most_one_value_set ((ex , px , exat , pxat , keepttl )):
54085444 raise DataError (
54095445 "``ex``, ``px``, ``exat``, ``pxat``, "
54105446 "and ``keepttl`` are mutually exclusive."
0 commit comments