
    ]jD                        d Z ddlZddlZddlZddlZddlZddlZddlZddlZddl	m
Z
mZmZ ddlmZmZmZmZmZmZmZ ddlmZ ddlmZ erddlmZ dd	lmZ dd
lmZ ddlm Z   ed      Z! ede"      Z#ee#e$f   Z% ejL                  e'      Z(de)ee$f   fdZ*deee!      de+e!   fdZ,dee-e$f   de$fdZ.ddde/ee-e$f   ef   de0de/e$ef   fdZ1de$dedef   fdZ2de$de3d   fdZ4de$de3d   fd Z5de$de3d!   fd"Z6d#e$de$fd$Z7d%e$de$fd&Z8dej                  fd'Z9d(Z:d)ej                  de$fd*Z;d+e$dej                  fd,Z<d-ede0fd.Z=ed-e$de+e$   fd/       Z>ed-dde+d   fd0       Z>ed-ede$eede$f      f   de+ede$f      fd1       Z>ed-ee#   de+e#   fd2       Z>ed-e#de+e#   fd3       Z>d4 Z>de?fd5Z@dNde3fd6ZAd7ee-e$f   dej                  fd8ZBd9eee?eCe$f      dee?   fd:ZDd;d<de)e?e?e?f   fd=ZEd> ZFd?ee!   d@e?de
ee!   ddf   fdAZGdNdBe$dCee?   de$fdDZH	 dNdEee$   dFedGe/eef   dCee?   dee$   f
dHZIdIeee$d!f      de+e$   fdJZJdIeee$d!f      ded<   fdKZKdLe$de)e$e$f   fdMZLy)Oz
Miscellaneous helper functions.

The formatter for ANSI colored console output is heavily based on Pygments
terminal colorizing code, originally by Georg Brandl.
    N)	GeneratorIterableSequence)TYPE_CHECKINGAnyCallableOptionalTypeVarUnionoverload)ResponseError   )TimeoutFormatError)RedisJobQueueWorker_T_O)boundreturnc                    t        j                  |       r| j                  | j                  fS t        j                  |       st        j
                  |       rd| j                   d| j                   fS t        | t              rdt        |       fS t        j                  |       st        | d      r| dfS t        d|        )a  Resolve a function reference into instance and function name components.

    Args:
        func: The function reference to resolve - can be a method, function,
             builtin, string path, or callable class instance.

    Returns:
        A tuple of (instance, func_name) where:
        - instance: The object instance (for methods/callable instances) or None
        - func_name: The string representation of the function name/path

    Raises:
        TypeError: If func is not a valid callable or string reference.
    N.__call__z*Expected a callable or a string, but got: )inspectismethod__self____name__
isfunction	isbuiltin
__module____qualname__
isinstancestras_textisclasshasattr	TypeError)funcs    2/root/env/lib/python3.12/site-packages/rq/utils.pyresolve_function_referencer.   1   s     }}dmm++			D	!W%6%6t%<($*;*;)<===	D#	WT]""__T"wtZ'@ZDTFKLL    lstc                 2    | D cg c]  }||	 c}S c c}w )zExcludes `None` values from a list-like object.

    Args:
        lst (list): A list (or list-like) object

    Returns:
        object (list): The list without None values
     )r0   items     r-   compactr4   L   s     !5TD$4D555s   vc                     t        | t              r| j                  d      S t        | t              r| S t	        dt        |       z        )zConverts a bytes value to a string using `utf-8`.

    Args:
        v (Union[bytes, str]): The value (bytes or string)

    Raises:
        ValueError: If the value is not bytes or string

    Returns:
        value (str): The decoded string
    zutf-8zUnknown type %r)r&   bytesdecoder'   
ValueErrortype)r5   s    r-   r(   r(   X   sA     !Uxx  	As	*T!W455r/   F)decode_valueshr;   c                    |r t        d | j                         D              S t        d | j                         D              S )a  Decodes the Redis hash, ensuring that keys are strings
    Most importantly, decodes bytes strings, ensuring the dict has str keys.

    Args:
        h (Dict[Any, Any]): The Redis hash
        decode_values (bool): If True, also decode values to strings using as_text(). Defaults to False.

    Returns:
        Dict[str, Any]: The decoded Redis data (Dictionary)
        When decode_values=True, returns Dict[str, str]
    c              3   N   K   | ]  \  }}t        |      t        |      f  y wNr(   .0kr5   s      r-   	<genexpr>z$decode_redis_hash.<locals>.<genexpr>y   s!     CAWQZ,Cs   #%c              3   <   K   | ]  \  }}t        |      |f  y wr?   r@   rA   s      r-   rD   z$decode_redis_hash.<locals>.<genexpr>z   s     6DAqQ6s   )dictitems)r<   r;   s     r-   decode_redis_hashrH   l   s5     CCCC6AGGI666r/   name.c                    | j                  d      }|dd |d   g}}d}t        |      r(	 dj                  |      }t        j                  |      }	 |
	 t        |    S dj                  |      }t        ||      rt        ||      S |j                         }dj                  |      }	 t        ||      }t        ||      st        d| z        t        ||      S # t
        $ r# |j                  d|j                                Y nw xY wt        |      r# t        $ r t        d|        w xY w#  t        d|z        xY w)a#  Returns an attribute from a dotted path name. Example: `path.to.func`.

    When the attribute we look for is a staticmethod, module name in its
    dotted path is not the last-before-end word

    E.g.: package_a.package_b.module_a.ClassA.my_static_method

    Thus we remove the bits from the end of the name until we can import it

    Args:
        name (str): The name (reference) to the path.

    Raises:
        ValueError: If no module is found or invalid attribute name.

    Returns:
        Any: An attribute (normally a Callable)
    r   Nr   zInvalid attribute name: zInvalid attribute name: %s)splitlenjoin	importlibimport_moduleImportErrorinsertpop__builtins__KeyErrorr9   r*   getattr)	rI   	name_bitsmodule_name_bitsattribute_bitsmodulemodule_nameattribute_nameattribute_owner_nameattribute_owners	            r-   import_attributer_   }   si   & 

3I'0"~	"nF

	=((#34K,,[9F ~	@%% XXn-Nv~&v~..#'')N88N3H!&*>? ?N35<==?N33/  	=!!!%5%9%9%;<	= 
  	@7v>??	@H5FGGs)   &C D )D2 )DDD/2Er   c                     t        |       }t        |t              st        d|        ddlm} t        ||      st        d|        |S )z.Import a worker class from a dotted path name.zInvalid worker class: r   r   )r_   r&   r:   r9   workerr   
issubclass)rI   clsr   s      r-   import_worker_classrd      sN    
4
 Cc4 1$899c6"1$899Jr/   r   c                     t        |       }t        |t              st        d|        ddlm} t        ||      st        d|        |S )z+Import a job class from a dotted path name.zInvalid job class: r   r   )r_   r&   r:   r9   jobr   rb   )rI   rc   r   s      r-   import_job_classrg      sN    
4
 Cc4 .tf566c3.tf566Jr/   r   c                     t        |       }t        |t              st        d|        ddlm} t        ||      st        d|        |S )z-Import a queue class from a dotted path name.zInvalid queue class: r   r   )r_   r&   r:   r9   queuer   rb   )rI   rc   r   s      r-   import_queue_classrj      sN    
4
 Cc4 0788c5!0788Jr/   config_pathc                 L   t         j                  j                  | v xs | j                  d      }|s| S | }|j                  d      r|dd }|j	                  t         j                  j                        r|dd }|j                  t         j                  j                  d      }|S )a"  Normalize configuration path to dotted module path format.

    Converts file paths like 'directory/config_file.py' or 'directory.config_file'
    to dotted module paths like 'directory.config_file' for use with importlib.import_module().

    Args:
        config_path: Either a file path (e.g., 'app/cron_config.py', 'app/cron_config')
                    or a dotted module path (e.g., 'app.cron_config')

    Returns:
        A dotted module path suitable for importlib.import_module()

    Examples:
        normalize_config_path('app/cron_config.py') -> 'app.cron_config'
        normalize_config_path('app/cron_config') -> 'app.cron_config'
        normalize_config_path('app.cron_config') -> 'app.cron_config'
        normalize_config_path('/abs/path/to/config.py') -> 'abs.path.to.config'
    z.pyNr   r   )ospathsependswith
startswithreplace)rk   is_file_path
normalizeds      r-   normalize_config_pathrv      s    ( 77;;+-L1E1Ee1LL J 5!_
 RWW[[)^
 ##BGGKK5Jr/   	file_pathc                     t         j                  j                  |       st        d|  d      t         j                  j	                  |       st        d|  d      | S )am  Validate that an absolute file path exists and points to a file.

    Args:
        file_path: The absolute file path to validate

    Returns:
        The same file path if validation passes (for chaining)

    Raises:
        FileNotFoundError: If the file does not exist
        IsADirectoryError: If the path points to a directory instead of a file

    Examples:
        validate_absolute_path('/path/to/config.py')  # Returns '/path/to/config.py'
        validate_absolute_path('/path/to/missing.py')  # Raises FileNotFoundError
        validate_absolute_path('/path/to/directory')   # Raises IsADirectoryError
    z!Configuration file not found at ''z7Configuration path points to a directory, not a file: ')rn   ro   existsFileNotFoundErrorisfileIsADirectoryError)rw   s    r-   validate_absolute_pathr~   
  sW    $ 77>>)$"CI;a PQQ77>>)$"YZcYdde fggr/   c                  p    t         j                   j                  t         j                  j                        S )zReturn now in UTC)datetimenowtimezoneutcr2   r/   r-   r   r   %  s%      !2!2!6!677r/   z%Y-%m-%dT%H:%M:%S.%fZdtc                 >    | j                  t        t                    S r?   )strftimer(   _TIMESTAMP_FORMAT)r   s    r-   	utcformatr   -  s    ;;w0122r/   stringc                     	 t         j                   j                  | t              }|j	                  t         j
                  j                        S # t        $ r# t         j                   j                  | d      }Y Uw xY w)Nz%Y-%m-%dT%H:%M:%SZ)tzinfo)r   strptimer   r9   rs   r   r   )r   parseds     r-   utcparser   1  sl    J""++F4EF >>!2!2!6!6>77  J""++F4HIJs   $A )A<;A<objc                 H    t        | t              xr t        | t               S )zReturns whether the obj is an iterable, but not a string

    Args:
        obj (Any): _description_

    Returns:
        bool: _description_
    )r&   r   r'   r   s    r-   is_nonstring_iterabler   :  s      c8$AZS-A)AAr/   c                      y r?   r2   r   s    r-   ensure_job_listr   F  s    ,/r/   c                      y r?   r2   r   s    r-   r   r   H  s    03r/   c                      y r?   r2   r   s    r-   r   r   J  s    ehr/   c                      y r?   r2   r   s    r-   r   r   L  s    47r/   c                      y r?   r2   r   s    r-   r   r   N  s    *-r/   c                 ^    t        | t              rt        | t              st        |       S | gS )zWhen passed an iterable of objects, convert to list, otherwise, it returns
    a list with just that object in it.

    Args:
        obj (Any): _description_

    returns:
        List: _description_
    )r&   r   r'   listr   s    r-   r   r   R  s)     #31*S#:N49YUXTYYr/   c                  X    t        j                  t               j                               S )zKReturns current UTC timestamp

    Returns:
        int: _description_
    )calendartimegmr   utctimetupler2   r/   r-   current_timestampr   a  s     ??35--/00r/   c                 X    |t        | |      S t        |t              rt        |      S |S )a  Get a backend class using its default attribute name or an override

    Args:
        holder (_type_): _description_
        default_name (_type_): _description_
        override (_type_, optional): _description_. Defaults to None.

    Returns:
        _type_: _description_
    )rV   r&   r'   r_   )holderdefault_nameoverrides      r-   backend_classr   j  s1     v|,,	Hc	"))r/   date_strc                     | st        d      t        | t              rt        | j	                               S t        |       S )Nz#Empty string or bytestring provided)r9   r&   r7   r   r8   )r   s    r-   str_to_dater   }  s8    >??h&HOO-..H%%r/   timeoutc                 V   t        | t        j                        s| 	 t        |       } | S | t        |       S dS # t        $ re t        | t
              sJ | dd | dd j                         }}ddddd}	 t        |      ||   z  } n# t        t        f$ r t        d      w xY wY |w xY w)	zGTransfer all kinds of timeout format to an integer representing secondsNrK   iQ i  <   r   )dr<   mszTimeout must be an integer or a string representing an integer, or a string with format: digits + unit, unit can be "d", "h", "m", "s", such as "1h", "23m".)	r&   numbersIntegralintr9   r'   lowerrU   r   )r   digitunitunit_seconds       r-   parse_timeoutr     s    gw//0W5H	'lGN #.3w<8D8  	gs+++!#2,(<(<(>4E %DrBKe*{4'88) (+  	s'   : :B(5BB(B""B('B(
connectionr   c                 t   	 t        | dd      st        | j                  d      d         }|j                  d      dd D cg c]  }t	        |       }}t        |      dk  r |j                  d       t        |      dk  r t        | dt        |             t        | d      S c c}w # t        $ r Y yw xY w)	a/  
    Returns tuple of Redis server version.
    This function also correctly handles 4 digit redis server versions.

    Args:
        connection (Redis): The Redis connection.

    Returns:
        version (Tuple[int, int, int]): A tuple representing the semantic versioning format (eg. (5, 0, 9))
    __rq_redis_server_versionNserverredis_versionr      r   )   r   	   )
rV   r'   inforL   r   rM   appendsetattrtupler   )r   version_striversion_partss       r-   get_versionr     s    z#>Ejooh7HIK-8->->s-CBQ-GHSVHMHm$q($$Q' m$q(+m$
 z#>?? I  s*   A B+ B&/B+ !B+ &B+ +	B76B7c                     |  |z   S )zCeiling division. Returns the ceiling of the quotient of a division operation

    Args:
        a (_type_): _description_
        b (_type_): _description_

    Returns:
        _type_: _description_
    r2   )abs     r-   ceildivr     s     R1W:r/   a_listsegment_sizec              #   V   K   t        dt        |       |      D ]  }| |||z      yw)zSplits a list into multiple smaller lists having size `segment_size`

    Args:
        a_list (Sequence[Any]): A sequence to split
        segment_size (int): The segment size to split into

    Yields:
        list: The splitted listed
    r   N)rangerM   )r   r   r   s      r-   
split_listr     s6      1c&k<0 +Q\)**+s   ')data
max_lengthc                 :    || S t        |       |kD  r| d| dz   S | S )a  Truncate arguments with representation longer than max_length

    Args:
        data (str): The data to truncate
        max_length (Optional[int], optional): The max length. Defaults to None.

    Returns:
        truncated (str): The truncated string
    Nz...)rM   )r   r   s     r-   truncate_long_stringr     s1     *-d)j*@D*%JdJr/   	func_nameargskwargsc                 H   | y|D cg c]   }t        t        t        |      |            " }}|j                         D cg c](  \  }}| dt        t        t        |      |             * }}}|t	        |      z  }dj                  |      }|  d| dS c c}w c c}}w )a  
    Returns a string representation of the call, formatted as a regular
    Python function invocation statement. If max_length is not None, truncate
    arguments with representation longer than max_length.

    Args:
        func_name (str): The function name
        args (Any): The function arguments
        kwargs (Dict[Any, Any]): The function kwargs
        max_length (int, optional): The max length. Defaults to None.

    Returns:
        str: A string representation of the function call.
    N=z, ())r(   r   reprrG   sortedrN   )	r   r   r   r   argarg_listrC   r5   list_kwargss	            r-   get_call_stringr     s    " PTU,T#Y
CDUHU[a[g[g[ijSWSTVWaS'"6tAw
"KLMNjKj{##H99XD[$q!! Vjs   %B-Bqueues_or_namesc                     ddl m} g }| D ]D  }t        ||      r|j                  |j                         +|j                  t        |             F |S )z;Given a iterable  of strings or queues, returns queue namesr   r   )ri   r   r&   r   rI   r'   )r   r   namesqueue_or_names       r-   parse_namesr     sM    E( -mU+LL++,LL]+,	-
 Lr/   c                 R    ddl m} | D ]  }t        ||      s|j                  c S  y)z7Given a list of strings or queues, returns a connectionr   r   N)ri   r   r&   r   )r   r   r   s      r-   get_connection_from_queuesr     s/    ( ,mU+ +++, r/   composite_keyc                     | j                  d      }t        |      dk(  r$t        j                  d|  t               |d   dfS |\  }}||fS )zMethod returns a parsed composite key.

    Args:
        composite_key (str): the composite key to parse

    Returns:
        tuple[str, str]: tuple of job id and the execution id
    :r   z4Composite key must contain job_id:execution_id, got r    )rL   rM   warningswarnDeprecationWarning)r   resultjob_idexecution_ids       r-   parse_composite_keyr     s`       %F
6{a 	B=/R	
 q	2!FLL!!r/   r?   )M__doc__r   r   rO   r   loggingr   rn   r   collections.abcr   r   r   typingr   r   r   r	   r
   r   r   redis.exceptionsr   
exceptionsr   redisr   rf   r   ri   r   ra   r   r   objectr   r'   ObjOrStr	getLoggerr!   loggerr   r.   r   r4   r7   r(   rF   boolrH   r_   r:   rd   rg   rj   rv   r~   r   r   r   r   r   r   r   r   r   r   floatr   r   r   r   r   r   r   r   r   r2   r/   r-   <module>r      sM         	  9 9   + * T]T S> 
		8	$Mc3h M6	6(2,' 	6DH 	66uUCZ  6S 6( QV 7eE3J/45 7 7Z^_bdg_gZh 7"243 248CH#5 24jc d8n 3 4; S T'] (s (s (Vc c 68X 8
 , 3(## 3 38S 8X.. 8	Bs 	Bt 	B 
 / /c / 
 /	 3 34; 3 
 3	 huc8E%*4E+FFG hDQVW\^aWaQbLc h 
 h	 7" 7$r( 7 
 7	 - -R - 
 -Z13 1$ &&%s
+ &0A0A &98E#uc/$:; 9 9,G c3m(< <
+x| +3 +9Xb\SWY]E];^ +Ks K K K  ^b"}"$'"15c3h"MUVY]"c]":
%W*=!> 
49 
sG|9L0M RZ[bRc "s "uS#X "r/   