~fddlZddlZddlZddlZddlZddlmZddlmZm Z m Z m Z m Z m Z mZddlmZddlmZmZmZmZddlmZmZmZmZddlmZmZmZmZddl m!Z!dd l"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)dd l*m+Z+dd l,m-Z-dd l.m/Z/m0Z0m1Z1m2Z2m3Z3d Z4dZ5dZ6Gdde7Z8GddZ9GddeeeZ:e:Z;GddZ<GddZ=Gddej|Z?Gdde:Z@y)N)chain)AnyCallableDictListOptionalTypeUnion)Encoder)_RedisCallbacks_RedisCallbacksRESP2_RedisCallbacksRESP3bool_ok) CoreCommandsRedisModuleCommandsSentinelCommands list_or_args)AbstractConnectionConnectionPool SSLConnectionUnixDomainSocketConnection)CredentialProvider)ConnectionErrorExecAbortError PubSubError RedisError ResponseError TimeoutError WatchErrorLock)Retry)HIREDIS_AVAILABLE_set_info_loggerget_lib_versionsafe_str str_if_bytesEMPTY_RESPONSE NEVER_DECODEcpeZdZdZdeeefddfdZfdZfdZfdZ d fd Z fd Z fd Z xZ S) CaseInsensitiveDictz?Case insensitive dict implementation. Assumes string keys only.datareturnNcZ|jD]\}}|||j<yN)itemsupper)selfr-kvs U/var/lib/jenkins/workspace/mettalog/venv/lib/python3.12/site-packages/redis/client.py__init__zCaseInsensitiveDict.__init__:s%JJLDAqDO!r(c>t||jSr0)super __contains__r2r3r4 __class__s r6r:z CaseInsensitiveDict.__contains__>sw#AGGI..r(c@t||jyr0)r9 __delitem__r2r;s r6r>zCaseInsensitiveDict.__delitem__As AGGI&r(c>t||jSr0)r9 __getitem__r2r;s r6r@zCaseInsensitiveDict.__getitem__Dsw"1779--r(c@t||j|Sr0)r9getr2)r3r4defaultr<s r6rBzCaseInsensitiveDict.getGsw{1779g..r(cBt||j|yr0)r9 __setitem__r2)r3r4r5r<s r6rEzCaseInsensitiveDict.__setitem__Js AGGIq)r(c:t|}t| |yr0)r,r9update)r3r-r<s r6rGzCaseInsensitiveDict.updateMs"4( tr(r0)__name__ __module__ __qualname____doc__rstrr7r:r>r@rBrErG __classcell__r<s@r6r,r,7sDE T#s(^  /'./*r(r,c eZdZy) AbstractRedisN)rHrIrJr(r6rPrPRsr(rPc+eZdZdZededdfdZededdeddfdZ dd d d d d d d d d d d d d ddd dd d dd d d dd ddd d d d d dd d de d d d d df+de e de e dd fdZdefdZd6dZdefdZde dfdZd7dZdededd fdZd8dZd9d:d Zd!edgd fdd fd"Z d;d#ed$e ed%ed&ed'e ed(ed efd)efd*Zd+Zd,Z d-Z!d.Z"d/Z#d0Z$d1Z%d2Z&d3Z'd4Z(d5Z)y )<Redisa Implementation of the Redis protocol. This abstract class provides a Python interface to all Redis commands and an implementation of the Redis protocol. Pipelines derive from this, implementing how the commands are sent and received to the Redis server. Based on configuration, an instance will either use a ConnectionPool, or Connection object to talk to redis. It is not safe to pass PubSub or Pipeline objects between threads. urlr.c x|jdd}tj|fi|}|||}d|_|S)a Return a Redis client object configured from the given URL For example:: redis://[[username]:[password]]@localhost:6379/0 rediss://[[username]:[password]]@localhost:6379/0 unix://[username@]/path/to/socket.sock?db=0[&password=password] Three URL schemes are supported: - `redis://` creates a TCP socket connection. See more at: - `rediss://` creates a SSL wrapped TCP socket connection. See more at: - ``unix://``: creates a Unix Domain Socket connection. The username, password, hostname, path and all querystring values are passed through urllib.parse.unquote in order to replace any percent-encoded values with their corresponding characters. There are several ways to specify a database number. The first value found will be used: 1. A ``db`` querystring option, e.g. redis://localhost?db=0 2. If using the redis:// or rediss:// schemes, the path argument of the url, e.g. redis://localhost/0 3. A ``db`` keyword argument to this function. If none of these options are specified, the default db=0 is used. All querystring options are cast to their appropriate Python types. Boolean arguments can be specified with string values "True"/"False" or "Yes"/"No". Values that cannot be properly cast cause a ``ValueError`` to be raised. Once parsed, the querystring arguments and keyword arguments are passed to the ``ConnectionPool``'s class initializer. In the case of conflicting arguments, querystring arguments always win. single_connection_clientFconnection_poolrVT)poprfrom_urlauto_close_connection_pool)clsrTkwargsrVrXclients r6rZzRedis.from_urlesKT$*::.H%#P (11#@@+%= -1) r(r\rXc&||}d|_|S)z Return a Redis client from the given connection pool. The Redis client will take ownership of the connection pool and close it when the Redis client is closed. )rXT)r[)r\rXr^s r6 from_poolzRedis.from_pools + -1) r( localhostirNzutf-8strictFrequiredzredis-pycredential_providerprotocolc,| s| tjtd| } | tjtd|} |sg}|dur|jtid|d|'d|d|d | d | d |d |d t j |(d|!d|#d|$d|%d|&d|)d|*d|+},| |,j| tdn>|,j|||||d|r%|,jt|||||||||||||| dtdi|,} d|_ nd|_ | |_ d|_ |"r |jjd|_ tt |_|jj$j'ddvr |j"jt(y|j"jt*y)a Initialize a new Redis client. To specify a retry policy for specific errors, first set `retry_on_error` to a list of the error/s to retry on, then set `retry` to a valid `Retry` object. To retry on TimeoutError, `retry_on_timeout` can also be set to `True`. Args: single_connection_client: if `True`, connection pool is not used. In that case `Redis` instance use is not thread safe. Nz/"charset" is deprecated. Use "encoding" insteadz5"errors" is deprecated. Use "encoding_errors" insteadTdbusernamepasswordsocket_timeoutencodingencoding_errorsdecode_responsesretry_on_errorretrymax_connectionshealth_check_interval client_namelib_name lib_versionredis_connect_funcrerf)pathconnection_class)hostportsocket_connect_timeoutsocket_keepalivesocket_keepalive_options)rx ssl_keyfile ssl_certfile ssl_cert_reqs ssl_ca_certs ssl_ca_datassl_check_hostname ssl_password ssl_ca_pathssl_validate_ocsp_stapledssl_validate_ocspssl_ocsp_contextssl_ocsp_expected_certssl_min_version ssl_ciphersF_)3rQ)warningswarnDeprecationWarningappendrcopydeepcopyrGrrrr[rX connectionget_connectionr,r response_callbacksconnection_kwargsrBrr )-r3ryrzrhrjrkr{r|r}rXunix_socket_pathrlrmcharseterrorsrnretry_on_timeoutrosslr~rrrrrrrrrrrrrrqrVrrrsrtrurirprvrerfr]s- r6r7zRedis.__init__smv" &I #! &O #)!!#4'%%l3bHH!.  H  "? #$4!.u-"?()>{H{%&8 &':!"H#F( + 0,F $ $2H,<4L MM0=+6,8-:,8+62D,8+69R1B0@6L/>+6&-6v6O.2D +.3D +. #"22AA#FDO"5o"F    1 1 5 5j AX M  # # * *+? @  # # * *+? @r(cdt|jdt|jdt|jdS)N<.(z)>)typerIrHreprrXr3s r6__repr__zRedis.__repr__BsDT %%&aT (;(;'<T))*+2 / r(c6|jjS)z!Get the connection pool's encoder)rX get_encoderrs r6rzRedis.get_encoderHs##//11r(c.|jjS)z'Get the connection's key-word arguments)rXrrs r6get_connection_kwargszRedis.get_connection_kwargsLs##555r(r"c@|jjdSNrp)rrBrs r6 get_retryzRedis.get_retryPs))+//88r(c||jjd|i|jj|yr)rrGrX set_retry)r3rps r6rzRedis.set_retrySs2 ""$++We,<= &&u-r(commandcallbackc"||j|<y)zSet a custom Response CallbackN)r)r3rrs r6set_response_callbackzRedis.set_response_callbackWs+3(r(ct|||y)a This function can be used to add externally defined redis modules, and their namespaces to the redis client. funcname - A string containing the name of the function to create func - The function, being added to this class. ex: Assume that one has a custom redis module named foomod that creates command named 'foo.dothing' and 'foo.anotherthing' in redis. To load function functions into this namespace: from redis import Redis from foomodule import F r = Redis() r.load_external_module("foo", F) r.foo().dothing('your', 'arguments') For a concrete example see the reimport of the redisjson module in tests/test_connection.py::test_loading_external_modules N)setattr)r3funcnamefuncs r6load_external_modulezRedis.load_external_module[s* h%r(PipelinecFt|j|j||S)a_ Return a new pipeline object that can queue multiple commands for later execution. ``transaction`` indicates whether all commands should be executed atomically. Apart from making a group of operations atomic, pipelines are useful for reducing the back-and-forth overhead between the client and server. )rrXr)r3 transaction shard_hints r6pipelinezRedis.pipeliners&  $"9"9;   r(rcx|jdd}|jdd}|jdd}|jd|5} |r|j|||}|j} |r|n| cdddS#t$r||dkDrt j |YbwxYw#1swYyxYw)z Convenience method for executing the callable `func` as a transaction while watching all keys specified in `watches`. The 'func' callable should expect a single argument which is a Pipeline object. rNvalue_from_callableF watch_delayTr)rYrwatchexecutertimesleep) r3rwatchesr]rrrpipe func_value exec_values r6rzRedis.transaction~sZZ d3 $jj)>Fjj5 ]]4 ,  " G,!%dJ!%J)<:*L  "".;? ;/  s* B0 .B%B-*B0,B--B00B9nametimeoutrblockingblocking_timeout lock_class thread_localc 0|t}||||||||S)aL Return a new Lock object using key ``name`` that mimics the behavior of threading.Lock. If specified, ``timeout`` indicates a maximum life for the lock. By default, it will remain locked until release() is called. ``sleep`` indicates the amount of time to sleep per loop iteration when the lock is in blocking mode and another client is currently holding the lock. ``blocking`` indicates whether calling ``acquire`` should block until the lock has been acquired or to fail immediately, causing ``acquire`` to return False and the lock not being acquired. Defaults to True. Note this value can be overridden by passing a ``blocking`` argument to ``acquire``. ``blocking_timeout`` indicates the maximum amount of time in seconds to spend trying to acquire the lock. A value of ``None`` indicates continue trying forever. ``blocking_timeout`` can be specified as a float or integer, both representing the number of seconds to wait. ``lock_class`` forces the specified lock implementation. Note that as of redis-py 3.0, the only lock class we implement is ``Lock`` (which is a Lua-based lock). So, it's unlikely you'll need this parameter, unless you have created your own custom lock class. ``thread_local`` indicates whether the lock token is placed in thread-local storage. By default, the token is placed in thread local storage so that a thread only sees its token, not a token set by another thread. Consider the following timeline: time: 0, thread-1 acquires `my-lock`, with a timeout of 5 seconds. thread-1 sets the token to "abc" time: 1, thread-2 blocks trying to acquire `my-lock` using the Lock instance. time: 5, thread-1 has not yet completed. redis expires the lock key. time: 5, thread-2 acquired `my-lock` now that it's available. thread-2 sets the token to "xyz" time: 6, thread-1 finishes its work and calls release(). if the token is *not* stored in thread local storage, then thread-1 would see the token value as "xyz" and would be able to successfully release the thread-2's lock. In some use cases it's necessary to disable thread local storage. For example, if you have code where one thread acquires a lock and passes that lock instance to a worker thread to release later. If thread local storage isn't disabled in this case, the worker thread won't see the token set by the thread that acquired the lock. Our assumption is that these cases aren't common and as such default to using thread local storage.)rrrrrr )r3rrrrrrrs r6lockz Redis.locks2|  J  -%  r(c .t|jfi|S)z Return a Publish/Subscribe object. With this object, you can subscribe to channels and listen for messages that get published to them. )PubSubrX)r3r]s r6pubsubz Redis.pubsubs d**5f55r(c,t|jSr0)MonitorrXrs r6monitorz Redis.monitorst++,,r(c<|j|jdS)NTrW)r<rXrs r6r^z Redis.clients#~~ 004  r(c|Sr0rQrs r6 __enter__zRedis.__enter__ r(c$|jyr0closer3exc_type exc_value tracebacks r6__exit__zRedis.__exit__  r(c$|jyr0rrs r6__del__z Redis.__del__rr(ct|dsy|j}|r"d|_|jj||jr|jj yy)Nr)hasattrrrXreleaser[ disconnectr3conns r6rz Redis.closesXt\*  "DO  ( ( .  * *  + + - +r(cH|j||j||fi|S)z7 Send a command and parse the response ) send_commandparse_response)r3r command_nameargsoptionss r6_send_command_parse_responsez"Redis._send_command_parse_responses. 4 "t""4AAAr(c|j|j!t|t|jdur|y)z Close the connection and raise an exception if retry_on_error is not set or the error is not one of the specified error types NF)rro isinstancetupler3rerrors r6_disconnect_raisezRedis._disconnect_raises?     '%t':':!;<EKFr(cBj}djxs|jfi jj fdfdjs|j SS#js|j wwxYw)z.Execute a command and return a parsed responserc2jgiSr0rrrrrr3sr6z'Redis.execute_command..%s(999,)-18r(c(j|Sr0)rrrr3s r6rz'Redis.execute_command..(sd44T5Ar()rXrrrpcall_with_retryr)r3rrpoolrrs``` @@r6execute_commandzRedis.execute_commands##Aw N"5$"5"5l"Ng"N #::--B ?? T"#4?? T"#s &A>> Bc L t|vr(|jd}|jtn|j}t|vr|jt||j vr|j ||fi|S|S#t$rt|vr |tcYSwxYw)z'Parses a response from the Redis serverT)disable_decoding)r* read_responserYrr)r)r3rrrresponses r6rzRedis.parse_response.s w&%33T3J L)%335 W $ KK ' 422 284**<8MWM M (~..  sABB#!B#)r.r )rpr"r.Nr.N)TNr.r)Ng?TNNT)*rHrIrJrK classmethodrLrZr rr`r%rrintr7rrrrrrrrrrrfloatboolr rrrrr^rrrrrrrrrQr(r6rSrSVsF 030W00d  '] '    "  #!%    "'#!&#%<@"#YXAV&&89WXAX3-YXAZ [XAt # 26t698G,9.4S4H44&.  j\4/0 6$(,0'+!H H %H  H  H #5/ H $)$H H T6-  .B #"r(rScveZdZdZej dZej dZdZdZ dZ dZ dZ y ) rz Monitor is useful for handling the MONITOR command to the redis server. next_command() method returns one command from monitor listen() method yields commands from monitor. z\[(\d+) (.*?)\] (.*)z"(.*?)(?!Q ##AT#2A5H DNN &X & ==BF--BUBUBW:>!Q ##AT#2A5H DOO 'h '   !//557Aq ##AT#2A5N DOO -n -   s8(F(F (Fc6|jjS)z@Indicates if there are subscriptions to any channels or patterns)rFis_setrs r6 subscribedzPubSub.subscribeds$$++--r(c|j|jjd|j|_|jj |j |j 5ts/|jjj|j |j}d|j i}|js|j|j||jg|i|y)z#Execute a publish/subscribe commandNr check_health)rrXrrregister_connect_callbackrVr@r#_parserset_push_handlerrgclean_health_check_responses_executer)r3rrr]s r6rzPubSub.execute_commands ?? ""22AA$//DO OO 5 5doo F%%1:K''889O9OP__  doo"56  - - / j*"9"9KDKFKr(cd}|j}|jdkDr|dkDr|j||j|jr]|j||j }|j |r|xjdzc_ntdj||dz}|jdkDr|dkDryyyy)zG If any health check responses are present, clean them rrrz?A non health check response was cleaned by execute_command: {0}N) rrWrncan_readrkris_health_check_responserformat)r3ttlrrs r6rmz#PubSub.clean_health_check_responsess0014q}}T4==$:M:M}N==t/A/AB00:66!;6%//5vh/? 1HC0014q44r(c|j|j!t|t|jdur||j y)z Close the connection and raise an exception if retry_on_error is not set or the error is not one of the specified error types. Otherwise, try to reconnect NF)rrorrconnectrs r6_disconnect_raise_connectz PubSub._disconnect_raise_connectsB     '%t':':!;<EK r(cVjjfdfdS)aU Connect manually upon disconnection. If the Redis server is down, this will fail and raise a ConnectionError as desired. After reconnection, the ``on_connect`` callback should have been called by the # connection to resubscribe us to any channels and patterns we were previously listening to ciSr0rQ)rrr]sr6rz!PubSub._execute..1sGT,V,r(c(j|Sr0)rxrs r6rz!PubSub._execute..2s$88uEr()rpr)r3rrrr]s`````r6rnzPubSub._execute(s"zz)) , E  r(c|j td|jfd}|j|}|j |r|xj dzc_y|S)z3Parse the response from a publish/subscribe commandNNpubsub connection not set: did you forget to call subscribe() or psubscribe()?ctsjsyjjddS)NrqFT)disconnect_on_error push_request)rrrwr)blockrrsr6try_readz'PubSub.parse_response..try_read@s6}}W}5 %%%d%S Sr(r)r RuntimeErrorrirnrsrW)r3rrrrrs `` @r6rzPubSub.parse_response5sq <F   T==x0  ( ( 2  . .! 3 .r(c6||j|jfvS)z Check if the response is a health check response. If there are no subscriptions redis responds to PING command with a bulk response, instead of a multi-bulk with "pong" and the response. )rJrIrs r6rszPubSub.is_health_check_responsePs(   & &  ( (   r(c|j}| td|jrVtj|jkDr4|j d|j d|xjdz c_yyy)Nr}PINGF)rir)rrrrrnext_health_checkrrHrWrs r6rizPubSub.check_health[sv <F   % %$))+8N8N*N   fd&?&?e  T  . .! 3 .+O %r(c |jj}|jj}|jDcic]\}}||||c}}Scc}}w)z normalize channel/pattern names to be either bytes or strings based on whether responses are automatically decoded. this saves us from coercing the value for each message coming in. )r"rGr#r1)r3r-rGr#r4r5s r6_normalize_keyszPubSub._normalize_keysgsN $$$$15>Avay!1$>>>sAc|rt|d|dd}tj|}|j||jdg|j }|j |}|jj||js!|jjd|_ |jj||S)aE Subscribe to channel patterns. Patterns supplied as keyword arguments expect a pattern name as the key and a callable as the value. A pattern's callable will be invoked automatically when a message is received on that pattern rather than producing a message via ``listen()``. rrN PSUBSCRIBE)rdictfromkeysrGrkeysrr]rgrFrYrWr^difference_update)r3rr] new_patternsret_vals r6rczPubSub.psubscribeqs Qab2D}}T* F#&$&&|Jl6G6G6IJ++L9  \*  ! ! % % '12D . ));;LIr(c|r7t|d|dd}|jtj|}n |j}|j j ||jdg|S)zj Unsubscribe from the supplied patterns. If empty, unsubscribe from all patterns. rrN PUNSUBSCRIBE)rrrrr]r^rGr)r3rr]s r6r=zPubSub.punsubscribesk Qab2D++DMM$,?@H}}H ))00:#t##N:T::r(c|rt|d|dd}tj|}|j||jdg|j }|j |}|jj||js!|jjd|_ |jj||S)aR Subscribe to channels. Channels supplied as keyword arguments expect a channel name as the key and a callable as the value. A channel's callable will be invoked automatically when a message is received on that channel rather than producing a message via ``listen()`` or ``get_message()``. rrN SUBSCRIBE)rrrrGrrrrXrgrFrYrWrZr)r3rr] new_channelsrs r6rbzPubSub.subscribes Qab2D}}T* F#&$&&{I\5F5F5HI++L9  \*  ! ! % % '12D . ));;LIr(c|r7t|d|dd}|jtj|}n |j}|j j ||jdg|S)zi Unsubscribe from the supplied channels. If empty, unsubscribe from all channels rrN UNSUBSCRIBE)rrrrrXrZrGr)r3rrXs r6r<zPubSub.unsubscribesk Qab2D++DMM$,?@H}}H ))00:#t##M9D99r() target_nodec|rt|d|dd}tj|}|j||jdg|j }|j |}|jj||js!|jjd|_ |jj||S)az Subscribes the client to the specified shard channels. Channels supplied as keyword arguments expect a channel name as the key and a callable as the value. A channel's callable will be invoked automatically when a message is received on that channel rather than producing a message via ``listen()`` or ``get_sharded_message()``. rrN SSUBSCRIBE)rrrrGrrrr[rgrFrYrWr\r)r3rrr]new_s_channelsrs r6rdzPubSub.ssubscribes Qab2Dt,f%&$&&|Ln6I6I6KL--n= "">2  ! ! % % '12D . //AA.Qr(c|r7t|d|dd}|jtj|}n |j}|j j ||jdg|S)zu Unsubscribe from the supplied shard_channels. If empty, unsubscribe from all shard_channels rrN SUNSUBSCRIBE)rrrrr[r\rGr)r3rr s_channelss r6r>zPubSub.sunsubscribesm Qab2D--dmmD.ABJ,,J //66zB#t##N:T::r(c#K|jr5|j|jd}|||jr4yyw)zBListen for messages on channels this client has been subscribed toT)rN)rghandle_messagerrs r6r5z PubSub.listens?oo**4+>+>T+>+JKH#oos AAArc |jsYtj}|jj|dur'tj|z }t d||z }ny|j |du|}|r|j ||Sy)a Get the next message if one is available, otherwise None. If timeout is specified, the system will wait for `timeout` seconds before returning. Timeout should be specified as a floating point number, or None, to wait indefinitely. TN)rr)rgrrFwaitmaxrr)r3r?r start_time time_spentrs r6 get_messagezPubSub.get_messagesJ$$))'2d:"YY[:5 c7Z#78&&go&P &&x1JK Kr(r9c2|d|gndg}|j|S)z' Ping the Redis server rr)r3r9rs r6pingz PubSub.ping s*%,$7 fX#t##T**r(cf|yt|tr |dk7rd|gnddg}t|d}|dk(r||d|d|d d }n|d k(r |dd|dd }n |d|d|dd }||jvr(|d k(rK|d}||jvr|jj ||j j|dn|d k(rK|d}||jvr|jj ||jj|dnJ|d}||jvr7|jj ||jj|d|js2|j s&|js|jj||jvrv|dk(r |j j|dd}nD|dk(r |jj|dd}n|jj|dd}|r ||y|S|d k7r|s |j ry|S)z Parses a pub/sub message. If the channel or pattern was subscribed to with a message handler, the handler is invoked instead of a parsed message being returned. NsPONGrCr(rr:rrdr)rpatternchannelr-rBr=r>rr;r)rr!r'UNSUBSCRIBE_MESSAGE_TYPESr^remover]rYr\r[rZrXrFr_PUBLISH_MESSAGE_TYPESrBr?) r3rr? message_typer9r s_channelrhandlers r6rzPubSub.handle_messagesO   h &.6'.A*QT~H#HQK0 : %$#A;#A;  G V #$  G%#A;  G 499 9~-"1+d???55<E+--11')2DdK--++GI,>E  V #)D,J,Jr( sleep_timedaemonexception_handlerPubSubWorkerThreadcv|jjD]\}}| td|d|jjD]\}}| td|d|jjD]\}}| td|dt ||||}|j |S)Nz Channel: 'z' has no handler registeredz Pattern: 'zShard Channel: ')rr)rXr1rr]r[rstart) r3rrrrrrrthreads r6 run_in_threadzPubSub.run_in_thread]s !% 3 3 5 GW!Jwi7R"STT!6!% 3 3 5 GW!Jwi7R"STT!6#'"5"5";";"= Iw!&yk1LM#> $ *V?P    r()NFNN)r.rr)Tr)Frr0)F)rFN)+rHrIrJrKrrrHr rr rrLr7rrrrKrrVpropertyrgrrmrxrnrrsrirrrcr=rbr<rdr>r5r rget_sharded_messagerrrrQr(r6rrs@ O2 */'+@D $(  )$  !xt 'EXECDISCARDUNWATCHcx||_d|_||_||_||_d|_|j y)NF)rXrrrrwatchingrK)r3rXrrrs r6r7zPipeline.__init__s8."4&$  r(r.c|Sr0rQrs r6rzPipeline.__enter__rr(c$|jyr0rNrs r6rzPipeline.__exit__rr(cD |jy#t$rYywxYwr0rPrs r6rzPipeline.__del__s"  JJL   rRc,t|jSr0)len command_stackrs r6__len__zPipeline.__len__s4%%&&r(cy)z1Pipeline instances should always evaluate to TrueTrQrs r6__bool__zPipeline.__bool__sr(Ncg|_t|_|jrB|jr6 |jj d|jj d|_d|_ |jr-|jj|jd|_yy#t$r|jjYmwxYw)NrF) rrYscriptsrrrrrrexplicit_transactionrXrrs r6rKzPipeline.resetsu  ==T__ -,,Y7--/  $)! ??  ( ( 9"DO # -**, -s5B--#CCc$|jy)zClose the pipelineNrNrs r6rzPipeline.closes  r(cn|jr td|jr tdd|_y)z Start a transactional block of the pipeline after WATCH commands are issued. End the transactional block with `execute`. z"Cannot issue nested calls to MULTIz:Commands without an initial WATCH have already been issuedTN)rrrrs r6multizPipeline.multis<  $ $AB B   L %)!r(c|js|ddk(r|js|j|i|S|j|i|S)NrWATCH)rrimmediate_execute_commandpipeline_execute_command)r3rr]s r6rzPipeline.execute_commandsL MMT!W/9R9R14114B6B B,t,,d=f==r(c|j|jr|jtd|j!t |t |jdur|jy)z Close the connection, reset watching state and raise an exception if we were watching, if retry_on_error is not set or the error is not one of the specified error types. =A ConnectionError occurred on while watching one or more keysNF)rrrKrrorrrs r6_disconnect_reset_raisez Pipeline._disconnect_reset_raisesj  == JJLO     '%t':':!;<E JJL Fr(cdjs-jjj_jj fdfdS)z Execute a command immediately, but don't auto-retry on a ConnectionError if we're already WATCHing a variable. Used when issuing WATCH or subsequent commands retrieving their values but before MULTI is called. rc2jgiSr0rrsr6rz4Pipeline.immediate_execute_command..$s(5D55l%)-4r(c(j|Sr0)rrs r6rz4Pipeline.immediate_execute_command..'s$66tUCr()rrXrrrpr)r3rrrrs```@@r6rz"Pipeline.immediate_execute_commands_Aw ''66|T__UD"DOzz))  D   r(c@|jj||f|S)ar Stage a command to be executed when execute() is next called Returns the current Pipeline object back so commands can be chained together, such as: pipe = pipe.set('foo', 'bar').incr('baz').decr('bang') At some other point, you can then run: pipe.execute(), which will execute all commands queued in the pipe. )rr)r3rrs r6rz!Pipeline.pipeline_execute_command*s! !!4/2 r(cvtdifg|difg}|j|Dcgc]\}}t|vs|c}}}|j|g} |j |dt|D]A\} } t| dvr|j | | dtf/ |j |dC |j |d} d|_ | td|D]\} } | j| | t| t|k7r%|jjt d|r|j!|| g} t#| |D]T\}}t%|t&s.|\}}|d}||j(vr|j(||fi|}| j |V| Scc}}w#t $r} |j d| fYd} ~ qd} ~ wwxYw#t $r7} |j| | dz| d|j | | fYd} ~ d} ~ wwxYw#t$r |r|ddwxYw) N)MULTI)rrrrFzWatched variable changed.z6Wrong number of response items from pipeline execution)r pack_commandsr)send_packed_commandrrr enumerateannotate_exceptionrrrinsertrrrraise_first_errorziprrQr)r3rcommandsraise_on_errorcmdsrrall_cmdsrrirrr-rcmdrs r6_execute_transactionzPipeline._execute_transaction9s[z2&'YO3DE++'+ MmdG~W/LT M  &&x0  "    C 0 $H-JAw+ q'!*^"<=>*'' C8 . **:s;H  89 9DAq OOAq ! x=CM ) OO & & (H    " "8X 6(H-FAsa+ # g#Aw 4#:#::=// =aK7KA KKN . } N " MM1a& ! ! "%*++Aq1ugajAMM1a&))* Qil"  sFF0 F0 F6"G 7H#6 G?GG H ),HH #H8cX|j|Dcgc]\}}| c}}}|j|g}|D],\}} |j|j||dfi|.|r|j |||Scc}}w#t$r} |j| Yd} ~ jd} ~ wwxYwrT)rrrrrr) r3rrrrrrrrrs r6_execute_pipelinezPipeline._execute_pipeline|s++,JgdAT,JK&&x0%MD' # 3 3 3JQ S7 ST&   " "8X 6-K! #"" #s A? &B B)B$$B)ct|D]3\}}t|ts|j||dz||d|y)Nrr)rrrr)r3rrrrs r6rzPipeline.raise_first_errorsBh'DAq!]+''1q5(1+a.A(r(cdjtt|}d|d|d|jd}|f|jddz|_y)Nrz Command # z (z) of pipeline caused error: rr)r(mapr&r)r3 exceptionnumberrrmsgs r6rzPipeline.annotate_exceptions]hhs8W-.3%(&^^A./ 1 ).."44 r(c |tj|||fi|}||jvr d|_|S|dk(rd|_|S)NFrT)rSrUNWATCH_COMMANDSr)r3rrrresults r6rzPipeline.parse_responsesM%%dJ PP 400 0!DM W $ DM r(c t|j}|j}|Dcgc]}|j}}|dg|}t |s0t ||D] \}}|r |d|j |_"yycc}w)Nz SCRIPT EXISTSz SCRIPT LOAD)listrrshaallrscript)r3r immediatesshasexistsexists r6 load_scriptszPipeline.load_scriptss~t||$22 &'!''?2T26{05%mQXX>AE1 (sBrrc|j|jr td|j!t |t |jdur|j |y)z Close the connection, raise an exception if we were watching, and raise an exception if retry_on_error is not set or the error is not one of the specified error types. rNF)rrrrorrrKrs r6_disconnect_raise_resetz Pipeline._disconnect_raise_resetse  ==O     '%t':':!;<E JJLK Fr(cjsjsgSjrjjs j r j n jjs-jjdj_ jjfdfdjS#jwxYw)z0Execute all the commands in the current pipelinercSr0rQ)rrrstacksr6rz"Pipeline.execute..se^.sd::4Gr()rrrrrrrrrrXrrrprrK)r3rrrrs``@@@r6rzPipeline.executes""T]]I <<       t88//G,,G''66wPD#DO ::--<G JJLDJJLs +%C!!C3c&|jdy)zg Flushes all previously queued commands See: https://redis.io/commands/DISCARD rNrrs r6discardzPipeline.discards Y'r(cV|jr td|jdg|S)z$Watches the values at keys ``names``z"Cannot issue a WATCH after a MULTIr)rrr)r3namess r6rzPipeline.watchs/  $ $AB B#t##G4e44r(cH|jxr|jdxsdS)z'Unwatches all previously specified keysrT)rrrs r6unwatchzPipeline.unwatchs!}}@!5!5i!@HDHr(rr)T)"rHrIrJrKrr7rrrr rr rrKrrrrrrrrrrrrrrrQrrrrrrQr(r6rrs$6 ''$#. )> 2 * ADAF  5 ?   86(5 IIr(r)Arr6rDrr itertoolsrtypingrrrrrr r redis._parsers.encodersr redis._parsers.helpersr r rrredis.commandsrrrrredis.connectionrrrrredis.credentialsrredis.exceptionsrrrrrrr redis.lockr! redis.retryr" redis.utilsr#r$r%r&r' SYM_EMPTYr)r*rr,rPrS StrictRedisrrThreadrrrQr(r6r)s  CCC+   1  ! $6  j /?jZ @&@&FjjZ$))$NXIuXIr(