U
    lufK:                     @   s   d Z dZdgZddlmZ ddlZddlZddlmZm	Z	m
Z
mZmZ ddlmZmZ ddlmZmZmZmZmZ d	ZG d
d deeZG dd deZdS )zCUse the HTMLParser library to parse HTML files that aren't too bad.MITHTMLParserTreeBuilder    )
HTMLParserN)CDataCommentDeclarationDoctypeProcessingInstruction)EntitySubstitutionUnicodeDammit)DetectsXMLParsedAsHTMLParserRejectedMarkupHTMLHTMLTreeBuilderSTRICTzhtml.parserc                   @   s|   e Zd ZdZdZdZdd Zdd Zdd	 ZdddZ	dddZ
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS ) BeautifulSoupHTMLParserzA subclass of the Python standard library's HTMLParser class, which
    listens for HTMLParser events and translates them into calls
    to Beautiful Soup's tree construction API.
    ignorereplacec                 O   s4   | d| j| _tj| f|| g | _|   dS )a  Constructor.

        :param on_duplicate_attribute: A strategy for what to do if a
            tag includes the same attribute more than once. Accepted
            values are: REPLACE (replace earlier values with later
            ones, the default), IGNORE (keep the earliest value
            encountered), or a callable. A callable must take three
            arguments: the dictionary of attributes already processed,
            the name of the duplicate attribute, and the most recent value
            encountered.           
        on_duplicate_attributeN)popREPLACEr   r   __init__already_closed_empty_elementZ_initialize_xml_detector)selfargskwargs r   ;/tmp/pip-unpacked-wheel-pg4vfqbd/bs4/builder/_htmlparser.pyr   .   s     	z BeautifulSoupHTMLParser.__init__c                 C   s   t |d S )N)r   )r   messager   r   r   errorJ   s    zBeautifulSoupHTMLParser.errorc                 C   s   | j ||dd}| | dS )zHandle an incoming empty-element tag.

        This is only called when the markup looks like <tag/>.

        :param name: Name of the tag.
        :param attrs: Dictionary of the tag's attributes.
        F)handle_empty_elementN)handle_starttaghandle_endtag)r   nameattrstagr   r   r   handle_startendtagZ   s    z*BeautifulSoupHTMLParser.handle_startendtagTc                 C   s   i }|D ]`\}}|dkrd}||kr\| j }|| jkr6qd|d| jfkrN|||< qd|||| n|||< d}q|  \}	}
| jj|dd||	|
d}|r|jr|r| j|dd | j	| | j
dkr| | dS )a3  Handle an opening tag, e.g. '<tag>'

        :param name: Name of the tag.
        :param attrs: Dictionary of the tag's attributes.
        :param handle_empty_element: True if this tag is known to be
            an empty-element tag (i.e. there is not expected to be any
            closing tag).
        N z"")
sourceline	sourceposF)check_already_closed)r   IGNOREr   getpossoupr!   Zis_empty_elementr"   r   appendZ	_root_tagZ_root_tag_encountered)r   r#   r$   r    Z	attr_dictkeyvalueZon_dupe	attrvaluer(   r)   r%   r   r   r   r!   i   s6    


    

z'BeautifulSoupHTMLParser.handle_starttagc                 C   s,   |r|| j kr| j | n| j| dS )zHandle a closing tag, e.g. '</tag>'
        
        :param name: A tag name.
        :param check_already_closed: True if this tag is expected to
           be the closing portion of an empty-element tag,
           e.g. '<tag></tag>'.
        N)r   remover-   r"   )r   r#   r*   r   r   r   r"      s    	z%BeautifulSoupHTMLParser.handle_endtagc                 C   s   | j | dS )z4Handle some textual data that shows up between tags.N)r-   handle_datar   datar   r   r   r3      s    z#BeautifulSoupHTMLParser.handle_datac                 C   s   | drt|dd}n$| dr8t|dd}nt|}d}|dk r| jjdfD ]B}|sbqXzt|g|}W qX tk
r } zW 5 d}~X Y qXX qX|szt|}W n& t	t
fk
r } zW 5 d}~X Y nX |pd}| | dS )zHandle a numeric character reference by converting it to the
        corresponding Unicode character and treating it as textual
        data.

        :param name: Character number, possibly in hexadecimal.
        x   XN   zwindows-1252u   �)
startswithintlstripr-   original_encoding	bytearraydecodeUnicodeDecodeErrorchr
ValueErrorOverflowErrorr3   )r   r#   Z	real_namer5   encodinger   r   r   handle_charref   s*    

z&BeautifulSoupHTMLParser.handle_charrefc                 C   s0   t j|}|dk	r|}nd| }| | dS )zHandle a named entity reference by converting it to the
        corresponding Unicode character(s) and treating it as textual
        data.

        :param name: Name of the entity reference.
        Nz&%s)r
   ZHTML_ENTITY_TO_CHARACTERgetr3   )r   r#   	characterr5   r   r   r   handle_entityref   s
    z(BeautifulSoupHTMLParser.handle_entityrefc                 C   s&   | j   | j | | j t dS )zOHandle an HTML comment.

        :param data: The text of the comment.
        N)r-   endDatar3   r   r4   r   r   r   handle_comment   s    
z&BeautifulSoupHTMLParser.handle_commentc                 C   s6   | j   |tdd }| j | | j t dS )zYHandle a DOCTYPE declaration.

        :param data: The text of the declaration.
        zDOCTYPE N)r-   rJ   lenr3   r   r4   r   r   r   handle_decl   s    
z#BeautifulSoupHTMLParser.handle_declc                 C   sN   |  dr$t}|tdd }nt}| j  | j| | j| dS )z{Handle a declaration of unknown type -- probably a CDATA block.

        :param data: The text of the declaration.
        zCDATA[N)upperr:   r   rL   r   r-   rJ   r3   )r   r5   clsr   r   r   unknown_decl  s    
z$BeautifulSoupHTMLParser.unknown_declc                 C   s0   | j   | j | | | | j t dS )z\Handle a processing instruction.

        :param data: The text of the instruction.
        N)r-   rJ   r3   Z_document_might_be_xmlr	   r4   r   r   r   	handle_pi  s    

z!BeautifulSoupHTMLParser.handle_piN)T)T)__name__
__module____qualname____doc__r+   r   r   r   r&   r!   r"   r3   rF   rI   rK   rM   rP   rQ   r   r   r   r   r   $   s   
7
(	
r   c                       sN   e Zd ZdZdZdZeZeee	gZ
dZd fdd	ZdddZd	d
 Z  ZS )r   zpA Beautiful soup `TreeBuilder` that uses the `HTMLParser` parser,
    found in the Python standard library.
    FTNc                    sl   t  }dD ]}||kr
||}|||< q
tt| jf | |pBg }|pJi }|| d|d< ||f| _dS )a  Constructor.

        :param parser_args: Positional arguments to pass into 
            the BeautifulSoupHTMLParser constructor, once it's
            invoked.
        :param parser_kwargs: Keyword arguments to pass into 
            the BeautifulSoupHTMLParser constructor, once it's
            invoked.
        :param kwargs: Keyword arguments for the superclass constructor.
        )r   Fconvert_charrefsN)dictr   superr   r   updateparser_args)r   rZ   Zparser_kwargsr   Zextra_parser_kwargsargr0   	__class__r   r   r   *  s    


zHTMLParserTreeBuilder.__init__c           	      c   s\   t |tr|dddfV  dS |g}|g}||g}t|||d|d}|j|j|j|jfV  dS )a  Run any preliminary steps necessary to make incoming markup
        acceptable to the parser.

        :param markup: Some markup -- probably a bytestring.
        :param user_specified_encoding: The user asked to try this encoding.
        :param document_declared_encoding: The markup itself claims to be
            in this encoding.
        :param exclude_encodings: The user asked _not_ to try any of
            these encodings.

        :yield: A series of 4-tuples:
         (markup, encoding, declared encoding,
          has undergone character replacement)

         Each 4-tuple represents a strategy for converting the
         document to Unicode and parsing it. Each strategy will be tried 
         in turn.
        NFT)known_definite_encodingsuser_encodingsZis_htmlexclude_encodings)
isinstancestrr   markupr=   Zdeclared_html_encodingZcontains_replacement_characters)	r   rc   Zuser_specified_encodingZdocument_declared_encodingr`   r^   r_   Ztry_encodingsZdammitr   r   r   prepare_markupC  s"    
z$HTMLParserTreeBuilder.prepare_markupc              
   C   sh   | j \}}t||}| j|_z|| |  W n* tk
r\ } zt|W 5 d}~X Y nX g |_dS )z{Run some incoming markup through some parsing process,
        populating the `BeautifulSoup` object in self.soup.
        N)rZ   r   r-   feedcloseAssertionErrorr   r   )r   rc   r   r   parserrE   r   r   r   re   t  s    


zHTMLParserTreeBuilder.feed)NN)NNN)rR   rS   rT   rU   Zis_xmlZ	picklable
HTMLPARSERNAMEr   r   featuresZTRACKS_LINE_NUMBERSr   rd   re   __classcell__r   r   r\   r   r     s   
    
1)rU   __license____all__html.parserr   syswarningsZbs4.elementr   r   r   r   r	   Z
bs4.dammitr
   r   Zbs4.builderr   r   r   r   r   ri   r   r   r   r   r   r   <module>   s   	 z