U
    MfL1                     @   s   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mZmZmZmZ edddeddddZd	d
 ZdddZdS )    N   )IDENTITY
NO_DEFAULTLazyListdeprecation_warningis_iterable_liketry_callvariadicTF)defaultexpected_typeget_all	casesenseis_user_inputtraverse_stringc                   s   |t k	rtd dd ttr0fdd
nfdd
 	fdddd	 
fd
dfdd t|dD ].\}}	 | |	|t|kd}
|
dk	r|
  S qt krdS S )a4  
    Safely traverse nested `dict`s and `Iterable`s

    >>> obj = [{}, {"key": "value"}]
    >>> traverse_obj(obj, (1, "key"))
    'value'

    Each of the provided `paths` is tested and the first producing a valid result will be returned.
    The next path will also be tested if the path branched but no results could be found.
    Supported values for traversal are `Mapping`, `Iterable`, `re.Match`,
    `xml.etree.ElementTree` (xpath) and `http.cookies.Morsel`.
    Unhelpful values (`{}`, `None`) are treated as the absence of a value and discarded.

    The paths will be wrapped in `variadic`, so that `'key'` is conveniently the same as `('key', )`.

    The keys in the path can be one of:
        - `None`:           Return the current object.
        - `set`:            Requires the only item in the set to be a type or function,
                            like `{type}`/`{type, type, ...}/`{func}`. If a `type`, return only
                            values of this type. If a function, returns `func(obj)`.
        - `str`/`int`:      Return `obj[key]`. For `re.Match`, return `obj.group(key)`.
        - `slice`:          Branch out and return all values in `obj[key]`.
        - `Ellipsis`:       Branch out and return a list of all values.
        - `tuple`/`list`:   Branch out and return a list of all matching values.
                            Read as: `[traverse_obj(obj, branch) for branch in branches]`.
        - `function`:       Branch out and return values filtered by the function.
                            Read as: `[value for key, value in obj if function(key, value)]`.
                            For `Iterable`s, `key` is the index of the value.
                            For `re.Match`es, `key` is the group number (0 = full match)
                            as well as additionally any group names, if given.
        - `dict`:           Transform the current object and return a matching dict.
                            Read as: `{key: traverse_obj(obj, path) for key, path in dct.items()}`.
        - `any`-builtin:    Take the first matching object and return it, resetting branching.
        - `all`-builtin:    Take all matching objects and return them as a list, resetting branching.

        `tuple`, `list`, and `dict` all support nested paths and branches.

    @params paths           Paths which to traverse by.
    @param default          Value to return if the paths do not match.
                            If the last key in the path is a `dict`, it will apply to each value inside
                            the dict instead, depth first. Try to avoid if using nested `dict` keys.
    @param expected_type    If a `type`, only accept final values of this type.
                            If any other callable, try to call the function on each result.
                            If the last key in the path is a `dict`, it will apply to each value inside
                            the dict instead, recursively. This does respect branching paths.
    @param get_all          If `False`, return the first matching result, otherwise all matching ones.
    @param casesense        If `False`, consider string dictionary keys as case insensitive.

    `traverse_string` is only meant to be used by YoutubeDL.prepare_outtmpl and is not part of the API

    @param traverse_string  Whether to traverse into objects as strings.
                            If `True`, any non-compatible object will first be
                            converted into a string and then traversed into.
                            The return value of that path will be a string instead,
                            not respecting any further branching.


    @returns                The result of the object traversal.
                            If successful, `get_all=True`, and the path branches at least once,
                            then a list of results is returned instead.
                            If no `default` is given and the last path branches, a `list` of results
                            is always returned. If a path ends on a `dict` that result will always be a `dict`.
    z=The is_user_input parameter is deprecated and no longer worksc                 S   s   t | tr|  S | S N)
isinstancestrcasefold)k r   :/tmp/pip-unpacked-wheel-zk9bgjdq/yt_dlp/utils/traversal.py<lambda>Y       ztraverse_obj.<locals>.<lambda>c                    s   t |  r| S d S r   )r   valr   r   r   r   \   r   c                    s   t  pt| fdS )Nargs)r   r   r   r   r   r   r   ^   r   c           
   	      s  d}d }d kr:	r:dks.t s.ttr6d}d}nd krJ}nttrtt}tdksvt|trtdd D st	tt
r}nt|fd}nttt
frd}tj fd	dD }ndkrd}ttjjrtjjd
ttjjr0 }nRtsLttjjjrR}n0ttj rj! }n	r~d}t"}nd}nJt rnd}ttjjrtjjd
ttjjrЈ# }nxtsttjjjrt$}nRttj r,tt$% f! & # }n	rDd}t$t"}nd}fdd|D }|sd'|}nbttr fdd# D }fdd|D pd }n ttjjr,ttjjrtjjd
stj(fdr
tj)fdntfdd# D d }nttj rtt*sLrnt+,t- %}W 5 Q R X n.tt"rtfdd& # D d }n0tt*tfrttjj.tjjjfrtt}t+,t-  }W 5 Q R X n(	rt+,t- t" }W 5 Q R X nttjjjrtt"rЈ/d\}}0dsl1dsl}d |0drd| }n|r|0dsd| }fdd}	|rtt2|	3|}n|	}||r|n|ffS )NF.Tr   r   c                 s   s   | ]}t |tV  qd S r   )r   type.0itemr   r   r   	<genexpr>o   s     z2traverse_obj.<locals>.apply_key.<locals>.<genexpr>r   c                 3   s   | ]} |d  V  qdS )r   Nr   )r    branch)
apply_pathis_lastobjr   r   r"   w   s    )keyvaluec                 3   s&   | ]\}}t  ||fd r|V  qdS )r   N)r   r    r   v)r'   r   r   r"      s       c                 3   s$   | ]\}}| |d fV  qdS )FNr   r)   )_traverse_objr%   r&   r   r   r"      s     c                    s2   i | ]*\}}|d k	s t k	r||d k	r*|n qS r   )r   r)   )r
   r   r   
<dictcomp>   s
     z3traverse_obj.<locals>.apply_key.<locals>.<dictcomp>c                 3   s"   | ]\}} |kr|V  qd S r   r   r)   r   r'   r   r   r"      s      c                 3   s"   | ]\}} |kr|V  qd S r   r   r)   r.   r   r   r"      s      /@z().z./c                    s^    d kr| S  dkr| j S  dr>t| j j dd  fdS  dkrL| jS td d S )Nr0   r   r   ztext()z#apply_specials is missing case for )attrib
startswithr   gettextSyntaxError)element)specialr   r   apply_specials   s    
z7traverse_obj.<locals>.apply_key.<locals>.apply_specials)4callabler   slicesetnextiterlenr   allAssertionErrortupler   list	itertoolschainfrom_iterablehttpcookiesMorseldictr'   r(   collectionsabcMappingvaluesr   xmletreeElementTreeElementreMatchgroupsr   items	enumerategroup	groupdictjoin__contains__r4   int
contextlibsuppress
IndexErrorSequence
rpartitionr3   endswithmapiterfind)
r'   r&   r%   	branchingresultr!   Ziter_objZxpath_r9   )r,   r$   r   r   r
   r   )r%   r'   r&   r8   r   	apply_key`   s    









(&

ztraverse_obj.<locals>.apply_keyc                 s   sD   t | }t|t}|tkrd S |D ]}d|fV  |}q"d|fV  d S )NFT)r>   r=   r   )iterableiteratorprevr!   r   r   r   	lazy_last   s    

ztraverse_obj.<locals>.lazy_lastc                    s  | f}d}d }t |ttttfD ]\}}sBt|trB| }|ttfkrd}dd |D }|tkrvt	|d f}q$t
|f}q$t|rt|d d  g }|D ]&}	 ||	|\}
}||
O }|| qtj|}q$|rt|tt
tfst|}||t|tfS )NFc                 s   s   | ]}|d i fkr|V  qd S r   r   )r    r&   r   r   r   r"      s      z3traverse_obj.<locals>.apply_path.<locals>.<genexpr>T)r	   r   bytesrJ   r<   r   r   anyr@   r=   rC   r:   inspect	signaturebindappendrD   rE   rF   rB   rc   )Z	start_objpath	test_typeobjshas_branchedr'   lastZfiltered_objsZnew_objsr&   re   results)rh   r   rl   	type_testr   r   r$      s0    

z traverse_obj.<locals>.apply_pathc                    sl    | ||\}}}t dd |D }rP|rP|r8| S |rLtkrHg S S d S |r\|d S |rh|rhi S d S )Nc                 s   s   | ]}|d i fkr|V  qd S r   r   r   r   r   r   r"     s      z6traverse_obj.<locals>._traverse_obj.<locals>.<genexpr>r   )r   Zexhaustr   )r&   rs   Zallow_emptyrt   rx   rv   Zis_dict)r$   r
   r   r   r   r,     s    z#traverse_obj.<locals>._traverse_objr   TN)r   r   r   r   rW   r?   )r&   r
   r   r   r   r   r   pathsindexrs   rf   r   )r,   rh   r$   r   r   r
   r   r   rl   r   ry   r   traverse_obj   s    B
|#
r|   c                 O   s"   t | fdd |D |ddiS )Nc                 s   s   | ]}dt |V  qdS ).N).)r	   )r    keysr   r   r   r"      s     zget_first.<locals>.<genexpr>r   F)r|   )r&   rz   kwargsr   r   r   	get_first  s    r   c                 C   s2   t | jt|D ]}|d k	r|s$|s|  S q|S r   )rc   r4   r	   )dZkey_or_keysr
   Zskip_false_valuesr   r   r   r   dict_get#  s    
r   )NT)collections.abcrK   r]   http.cookiesrG   ro   rD   rS   xml.etree.ElementTreerO   _utilsr   r   r   r   r   r   r	   r|   r   r   r   r   r   r   <module>   s$   $      