U
    guC                     @  s.  d dl m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Zd dlZddlmZmZmZmZmZmZmZmZmZmZmZmZ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dZ$G dd deZ%ej&dddddddZ'ej&ddddddddZ'd4ddddddZ'ej&dddddddd d!Z(ej&dd"dd#d$d!Z(ej&dddddd%d&d!Z(ej&dd"dd'd(d!Z(ddddddd)d*d!Z(ej&dd"dd#d+d,Z)ej&dddddddd-d,Z)dddddd.d/d,Z)d0d1 Z*d5d2d3Z+dS )6    )annotationsN   )IDENTITY
NO_DEFAULTExtractorErrorLazyListdeprecation_warningget_elements_html_by_classget_elements_html_by_attributeget_elements_by_attributeget_element_html_by_attributeget_element_by_attributeget_element_html_by_idget_element_by_idget_element_html_by_classget_elements_by_class get_element_text_and_html_by_tagis_iterable_liketry_callurl_or_none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 ]r\}}	|t|k}
z$ | |	|
d}|dk	r|W   S W q tk
r } z|
rt|j|j	ddW 5 d}~X Y qX qt krdS S )a  
    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.
        - `filter`-builtin: Return the value if it is truthy, `None` otherwise.

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

    @params paths           Paths by which to traverse.
    @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-q5ljy6pj/yt_dlp/utils/traversal.py<lambda>k       ztraverse_obj.<locals>.<lambda>c                   s   t |  r| S d S r   )r   valr   r"   r#   r$   n   r%   c                   s   t  pt| fdS )Nargs)r   r   r&   r(   r"   r#   r$   p   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>   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/      s    )keyvaluec                 3  s&   | ]\}}t  ||fd r|V  qdS )r)   N)r   r-   r!   vr4   r"   r#   r/      s       c                 3  s$   | ]\}}| |d fV  qdS )FNr"   r6   )_traverse_objr2   r3   r"   r#   r/      s     c                   s2   i | ]*\}}|d k	s t k	r||d k	r*|n qS r   )r   r6   )r   r"   r#   
<dictcomp>   s
     z3traverse_obj.<locals>.apply_key.<locals>.<dictcomp>c                 3  s"   | ]\}} |kr|V  qd S r   r"   r6   r    r4   r"   r#   r/      s      c                 3  s"   | ]\}} |kr|V  qd S r   r"   r6   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 )Nr>   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dictr4   r5   collectionsabcMappingvaluesr   xmletreeElementTreeElementreMatchgroupsr   items	enumerategroup	groupdictjoin__contains__rB   int
contextlibsuppress
IndexErrorSequence
rpartitionrA   endswithmapiterfind)
r4   r3   r2   	branchingresultr.   Ziter_objZxpath_rG   )r:   r1   r    r   r   r   )r2   r4   r3   rF   r#   	apply_keyr   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)rL   rK   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krtd |}q$t|rt|d d  g }|D ]&}	 ||	|\}
}||
O }|| qtj|}q$|rt|tt
tfst|}||t|tfS )NFc                 s  s   | ]}|d i fkr|V  qd S r   r"   )r-   r3   r"   r"   r#   r/     s      z3traverse_obj.<locals>.apply_path.<locals>.<genexpr>T)r   r   bytesrX   rJ   r   r    anyrN   rK   rQ   filterrH   inspect	signaturebindappendrR   rS   rT   rP   rq   )Z	start_objpath	test_typeobjshas_branchedr4   lastZfiltered_objsZnew_objsr3   rs   results)rv   r   rz   	type_testr"   r#   r1      s6    


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   )r3   r   Zallow_emptyr   r   r   Zis_dict)r1   r   r   r"   r#   r:   !  s    z#traverse_obj.<locals>._traverse_objr   TNexpected)
r   r   r   r+   re   rM   _RequiredErrorr   Zorig_msgr   )r3   r   r   r   r   r   r   pathsindexr   r2   rt   er"   )r:   rv   r1   r    r   r   r   r   rz   r   r   r#   traverse_obj%   s(    C
|'&r   c                  s    fddS )Nc                   s    S r   r"   )ru   r5   r"   r#   r$   <  r%   zvalue.<locals>.<lambda>r"   r   r"   r   r#   r5   ;  s    r5   r   c                 s    fdd}|S )Nc                   s   | d krt d  d| S )NzUnable to extract r   )r   r   r   namer"   r#   func@  s    zrequire.<locals>.funcr"   )r   r   r   r"   r   r#   require?  s    r   c                   @  s   e Zd ZdS )r   N)__name__
__module____qualname__r"   r"   r"   r#   r   I  s   r   extz
str | Nonez=collections.abc.Callable[[list[dict]], dict[str, list[dict]]])r   returnc                 C  s   d S r   r"   r   r"   r"   r#   subs_list_to_dictM  s    r   zlist[dict] | Nonezdict[str, list[dict]])subsr   r   c               C  s   d S r   r"   )r   r   r"   r"   r#   r   Q  s    )r   c               C  s   | dkrt jt|dS tt}| D ]\}t|dsB|dsBq$|dd}|dkrXq$|dk	rr|dsr||d< || 	| q$t
|}| D ]} | jdd d	 q|S )
ax  
    Convert subtitles from a traversal into a subtitle dict.
    The path should have an `all` immediately before this function.

    Arguments:
    `ext`      The default value for `ext` in the subtitle dict

    In the dict you can set the following additional items:
    `id`       The subtitle id to sort the dict into
    `quality`  The sort order for each subtitle
    Nr   urldataidr   c                 S  s   |  ddpdS )NZqualityr   )pop)xr"   r"   r#   r$   r  r%   z#subs_list_to_dict.<locals>.<lambda>r8   )	functoolspartialr   rY   defaultdictrQ   r   rB   r   r   rX   r\   sort)r   r   rt   subZsub_idr"   r"   r#   r   U  s     
taghtmlr   )attrr5   r   c                 C  s   d S r   r"   r   r5   r   r   r"   r"   r#   find_elementw  s    r   r   )clsc                 C  s   d S r   r"   r   r   r"   r"   r#   r   {  s    )r   r   c                 C  s   d S r   r"   )r   r   r   r"   r"   r#   r     s    r   c                 C  s   d S r   r"   r   r"   r"   r#   r     s    )r   r   r   r   r5   r   c                   s   s|s|s|r|st ds$d|rb|rb|r8t d|rDt d|rLtnt}tj|||dS |r|rrt dd kst d|rtnt}t||S |r|rtnt}tj||dS t	t
|  fdd	S )
Nz3One of tag, id, cls or (attr AND value) is required[\w:.-]+Cannot match both attr and clszCannot match both attr and idr   zCannot match both cls and idCannot match both cls and tagc                   s   t |   S r   )r   r   r   r   r"   r#   r$     r%   zfind_element.<locals>.<lambda>)rO   r   r   r   r   r   r   r   r   rj   bool)r   r   r   r   r5   r   r   r"   r   r#   r     s$    c                 C  s   d S r   r"   r   r"   r"   r#   find_elements  s    r   c                 C  s   d S r   r"   r   r"   r"   r#   r     s    )r   r   r   r5   r   c                 C  sn   |s|r|st d|rJ|rJ|r(t d|r0tnt}tj|||| pDddS | rVt d|r^tnt}t||S )Nz*One of cls or (attr AND value) is requiredr   r   r   r   )rO   r
   r   r   r   r	   r   )r   r   r   r5   r   r   r"   r"   r#   r     s    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   )r3   r   kwargsr"   r"   r#   	get_first  s    r   c                 C  s2   t | jt|D ]}|d k	r|s$|s|  S q|S r   )rq   rB   r   )dZkey_or_keysr   Zskip_false_valuesr'   r"   r"   r#   dict_get  s    
r   )N)NT),
__future__r   rY   collections.abcrk   r   http.cookiesrU   r~   rR   ra   typingxml.etree.ElementTreer]   _utilsr   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r5   r   r   overloadr   r   r   r   r   r"   r"   r"   r#   <module>   sX   T      
"