U
    Sh~W                     @  s   d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZmZmZ ddlmZ ddlmZ ddlmZmZ e	rddlm Z  G dd de!Z"G dd dZ#G dd dZ$G dd dZ%G dd dZ&G dd deZ'dS )zThis module provides classes to Mock the core components of the docutils.RSTParser,
the key difference being that nested parsing treats the text as Markdown not rST.
    )annotationsN)Path)TYPE_CHECKINGAny)nodes)	DirectiveDirectiveError)Parser)Include)BodyInlinerRSTStateMachine)
StringList)unescape   )MarkupErrorparse_directive_text)DocutilsRendererc                   @  s   e Zd ZdZdS )MockingErrorzFAn exception to signal an error during mocking of docutils components.N)__name__
__module____qualname____doc__ r   r   F/root/rtd-docs/venv/lib/python3.8/site-packages/myst_parser/mocking.pyr      s   r   c                   @  sV   e Zd ZdZddddZddddd	d
dZddddddddZddddZdS )MockInlinerzdA mock version of `docutils.parsers.rst.states.Inliner`.

    This is parsed to role functions.
    r   )rendererc                   sN   | _ |j _|jj _|j _|j _t jdsD fdd j_d _	dS )zInitialize the mock inliner.get_source_and_linec                   s    j d | fS )NsourcedocumentZliselfr   r   <lambda>1       z&MockInliner.__init__.<locals>.<lambda>z
rfc%d.htmlN)
	_rendererr    reporterlanguage_module_rstlanguagecurrent_nodeparenthasattrr   Zrfc_url)r#   r   r   r"   r   __init__%   s    
zMockInliner.__init__strznodes.system_messageznodes.problematic)text	rawsourcemessagereturnc                 C  s:   | j || j}tj|||d}| j |}|| |S )z%Record a system message from parsing.)Zrefid)r    Zset_idr+   r   problematicZadd_backref)r#   r/   r0   r1   msgidr3   Zprbidr   r   r   r3   5   s
    
zMockInliner.problematicintr   z
nodes.Nodez3tuple[list[nodes.Node], list[nodes.system_message]])r/   linenomemor+   r2   c              
   C  sT   | j |8 t }| j | | j j||dd W 5 Q R X W 5 Q R X |jg fS )z*Parse the text and return a list of nodes.T)inline)r&   current_node_contextr   ZElementnested_render_textchildren)r#   r/   r6   r7   r+   	containerr   r   r   parse?   s
    
&zMockInliner.parsenamec                 C  sd   t t|r6t| j d| d}t|t d t| j d| }t|t d dS This method is only be called if the attribute requested has not
        been defined. Defined attributes will not be overridden.
        $ has not yet implemented attribute ''   z has no attribute N)r,   r   typer   r   with_tracebacksysexc_infor#   r?   msgr   r   r   __getattr__R   s
    
zMockInliner.__getattr__N)r   r   r   r   r-   r3   r=   rK   r   r   r   r   r      s
   
r   c                   @  s   e Zd ZdZddddddZddd	d
ddddZd4ddddddddZddddZddddddZe	
dZd dd!d"d#d$Zd5dd&d'd(Zd)d* Zd+d,d-d.Zd+d,d/d0Zdd1d2d3ZdS )6	MockStatezA mock version of `docutils.parsers.rst.states.RSTState`.

    This is parsed to the `Directives.run()` method,
    so that they may run nested parses on their content that will be parsed as markdown,
    rather than RST.
    r   MockStateMachiner5   )r   state_machiner6   c                   sL    _ |_ j_ jj_|_t _G  fddd}|_d S )Nc                      sB   e Zd ZU jZjjZ jZg Zded< e	 j
ZdZjZdS )z"MockState.__init__.<locals>.Struct	list[str]title_stylesFN)r   r   r   r    r'   r(   r)   rP   __annotations__maxZ_level_to_sectionZsection_levelZsection_bubble_up_kludgeinlinerr   r   r#   r   r   Structs   s   

rU   )r&   _linenor    r'   rN   r   rS   r7   )r#   r   rN   r6   rU   r   rT   r   r-   f   s    

	zMockState.__init__r   ztype[Directive]dict[str, Any]z1tuple[list[str], dict[str, Any], StringList, int])contentline_offset	directiveoption_presetsr2   c                 C  s`   |rt dt|dd|}|jr>tddd |jD |j|jt|j|j	d||j
 fS )zParse the full directive text

        :raises MarkupError: for errors in parsing the directive
        :returns: (arguments, options, content, content_offset)
        z5parse_directive_block: option_presets not implemented 
,c                 s  s   | ]}|j V  qd S N)rJ   ).0wr   r   r   	<genexpr>   s     z2MockState.parse_directive_block.<locals>.<genexpr>)r   )r   r   joinwarningsr   	argumentsoptionsr   bodyr   Zbody_offset)r#   rX   rY   rZ   r[   parsedr   r   r   parse_directive_block~   s    zMockState.parse_directive_blockFNnodes.ElementboolNone)blockinput_offsetnodematch_titlesr2   c              	   C  sR   | j j}| j|, | jjd|| j| |r4|ndd W 5 Q R X || j _dS )a  Perform a nested parse of the input block, with ``node`` as the parent.

        :param block: The block of lines to parse.
        :param input_offset: The offset of the first line of block,
            to the starting line of the state (i.e. directive).
        :param node: The parent node to attach the parsed content to.
        :param match_titles: Whether to to allow the parsing of headings
            (normally this is false,
            since nested heading would break the document structure)
        r]   N)Ztemp_root_node)rN   rp   r&   r9   r:   rc   rV   )r#   rm   rn   ro   rp   Zstate_machine_classZstate_machine_kwargsZsm_match_titlesr   r   r   nested_parse   s    
zMockState.nested_parser6   c                 C  s    d dd |D }dt|fS )z
        Taken from https://github.com/docutils-mirror/docutils/blob/e88c5fb08d5cdfa8b4ac1020dd6f7177778d5990/docutils/parsers/rst/states.py#L1927
        r\   c                 S  s   g | ]}d  | qS )r\   )rc   split)r`   liner   r   r   
<listcomp>   s     z*MockState.parse_target.<locals>.<listcomp>Zrefuri)rc   r   )r#   rm   
block_textr6   	referencer   r   r   parse_target   s    
zMockState.parse_targetr.   z/tuple[list[nodes.Element], list[nodes.Element]])r/   r6   r2   c                 C  s   | j ||| j| jjS )z`Parse text with only inline rules.

        :returns: (list of nodes, list of messages)
        )rS   r=   r7   r&   r*   )r#   r/   r6   r   r   r   inline_text   s    zMockState.inline_textu   ^((?:---?(?!-)|—) *)(.+)rO   list[nodes.Element])linesrY   r2   c                 C  sP  g }d}|}g }d}t |D ]\}}	|	 s2d}q|s<d}qd}| j|	}
|
sRq|}|
dg}||d d D ]<}|t|
dd }t|t| kr q|| qr|d| } qqt	 }| 
||| || |rLd|}| j| |pd }| ||\}}tj|df| }| j|\|_|_||7 }||7 }|S )	zParse a block quote, which is a block of text,
        followed by an (optional) attribution.

        ::

           No matter where you go, there you are.

           -- Buckaroo Banzai
        FNTrD   r   r]   r   r\   )	enumeratestripattribution_patternmatchgrouplenlstripappendr   block_quoterq   rc   rV   ry   attributionrN   r   r   rt   )r#   r{   rY   elementsZlast_line_blankZblockquote_linesZattribution_linesZattribution_line_offsetirt   r   Zat_lineZindented_lineZ
blockquoteZattribution_textr6   Z	textnodesmessagesr   r   r   r   r      sP    



zMockState.block_quoter   )stub_columnsc                 C  s   t | ||||S r_   )r   build_table)r#   Z	tabledata	tableliner   widthsr   r   r   r     s    zMockState.build_tablec                 C  s   t | ||S r_   )r   build_table_row)r#   Zrowdatar   r   r   r   r     s    zMockState.build_table_rowznodes.line_block)rm   c                 C  sJ   t dt|D ],}t|| dddkr||d  j|| _q| | dS )zModify the line block element in-place, to nest line block segments.

        Line nodes are placed into child line block containers, based on their indentation.
        r   indentN)ranger   getattrr   _nest_line_block_segment)r#   rm   indexr   r   r   nest_line_block_lines
  s    zMockState.nest_line_block_linesc                 C  s   dd |D }t |}g }t }|D ]H}|j|kr@|| q&t|rd| | || t }|| q&t|r| | || ||d d < d S )Nc                 S  s   g | ]
}|j qS r   )r   )r`   itemr   r   r   ru     s     z6MockState._nest_line_block_segment.<locals>.<listcomp>)minr   Z
line_blockr   r   r   r   )r#   rm   indentsZleastZ	new_itemsZ	new_blockr   r   r   r   r     s     




z"MockState._nest_line_block_segmentr>   c                 C  sN   t | j}tt|r$| d| dn| d| d}t|t d dS )rA   rB   z'. You can parse RST directly via the `{{eval-rst}}` directive: https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html#how-directives-parse-contentz has no attribute 'rC   rD   N)rE   r   r,   r   r   rF   rG   rH   )r#   r?   clsrJ   r   r   r   rK   '  s    
zMockState.__getattr__)FNN)r   N)r   r   r   r   r-   ri   rq   rx   ry   recompiler~   r   r   r   r   r   rK   r   r   r   r   rL   ^   s       

7
rL   c                   @  sN   e Zd ZdZdddddZddd	d
dZddd	ddZddddZdS )rM   z{A mock version of `docutils.parsers.rst.states.RSTStateMachine`.

    This is parsed to the `Directives.run()` method.
    r   r5   )r   r6   c                 C  s8   || _ || _|j| _|j| _| jj| _|j| _d| _d S )NT)	r&   rV   r    r(   r)   r'   r*   ro   rp   )r#   r   r6   r   r   r   r-   <  s    
zMockStateMachine.__init__Nz
int | Nonerr   c                 C  s
   | j d S )zReturn document source path.r   r   r#   r6   r   r   r   
get_sourceE  s    zMockStateMachine.get_sourcec                 C  s   | j d |p| jfS )zBReturn (source path, line) tuple for current or given line number.r   )r    rV   r   r   r   r   r   I  s    z$MockStateMachine.get_source_and_liner.   r>   c                 C  sd   t t|r6t| j d| d}t|t d t| j d| }t|t d dS r@   )r,   r   rE   r   r   rF   rG   rH   rI   r   r   r   rK   M  s
    
zMockStateMachine.__getattr__)N)N)r   r   r   r   r-   r   r   rK   r   r   r   r   rM   6  s
   	rM   c                   @  sF   e Zd ZdZddddddddd	d
ZddddZddddZdS )MockIncludeDirectivea   This directive uses a lot of statemachine logic that is not yet mocked.
    Therefore, we treat it as a special case (at least for now).

    See:
    https://docutils.sourceforge.io/docs/ref/rst/directives.html#including-an-external-document-fragment
    r   r.   r
   rO   rW   r5   )r   r?   klassre   rf   rg   r6   c                 C  s6   || _ |j| _|| _|| _|| _|| _|| _|| _d S r_   )r   r    r?   r   re   rf   rg   r6   )r#   r   r?   r   re   rf   rg   r6   r   r   r   r-   `  s    
zMockIncludeDirective.__init__rz   )r2   c                   s  ddl m}m} | jjjs.tdd| j dt| jd 	 j
}ddd	 | jd  D }|d
r|drt| jj|dd  nJz| jjj}W n tk
r   Y n X || jd \}}|| t| |  | jjjt  | jd| jjj}| jjj}z j||d}	W n tk
rj }
 z"tdd| j dt |
W 5 d }
~
X Y nF t k
r }
 z&tdd| j d  d|
 d|
W 5 d }
~
X Y nX | j!j"d k	r|	g}tt#j$j% | j!j"j&d}t| j!jd j'}| j!j"j(j)*d||| |d }	| jdd }| jdd }d|	 || }	|pJd}dD ]}| j|d }|slqP|	+|}|dk rtdd| j d| d| d|dkr||t,| 7 }|	|t,| d  }	n|	d | }	qPd| jkrt-j.|	t | jdg d }d|_/| 0| d!| jkrzt1| jd! p8d}W n0 t2k
rn } ztd"d#|W 5 d }~X Y nX |t,|	  }|	dr|	d d }	|g |	fg||}|D ]4\}}|r|t-j3|||d$7 }n|t-4|7 }qn|t-4|	7 }|gS d%| jkrht | jd< t5| j!| j6}t7| j!|| j6}|| j| j8d%g| j|	 | j6d|	||d&	}|9 S | j!jd }| j!j:j;}t<| j!j:d'd }zt | j!jd< t | j!j:_; fd*d+| j!j:_>d(| jkrt#j$% j
|| j!j=d(< d)| jkr
| jd) | j
f| j!j=d)< | j!j?|	|d | jd,dd- W 5 || j!jd< || j!j:_;| j!j=8d(d  | j!j=8d)d  |d k	rz|| j!j:_>n| j!j:`>X g S ).Nr   )	CodeBlockNumberLinesrD   zDirective "z" disabled.r   r\   c                 S  s   g | ]}|  qS r   )r}   )r`   sr   r   r   ru   z  s     z,MockIncludeDirective.run.<locals>.<listcomp><>r   encoding)r   errors   z": file not found: z": error reading file: r]   .)startzinclude-readz
start-linezend-line)start-afterz
end-beforez"; option "z": text not found "z".r   literalclass)r   classesznumber-lines   z+:number-lines: with non-integer start value)r   code)	r?   re   rf   rX   r6   Zcontent_offsetrv   staterN   r   zrelative-imageszrelative-docsc                   s   t  | fS r_   )r.   r!   pathr   r   r$     r%   z*MockIncludeDirective.run.<locals>.<lambda>zheading-offset)Zheading_offset)@Z$docutils.parsers.rst.directives.bodyr   r   r    settingsZfile_insertion_enabledr   r?   r   absoluter+   rc   re   
splitlines
startswithendswithr   Zstandard_include_pathjoinpathenvAttributeErrorZ
relfn2pathZnote_includedZrecord_dependenciesaddr.   rf   getZinput_encodingZinput_encoding_error_handler	read_textFileNotFoundError	Exceptionr   
sphinx_envosr   relpathsrcdirstemZappeventsemitfindr   r   literal_blockrt   add_namer5   
ValueErrorr8   TextrM   r6   rL   poprunr'   r   r   Zmd_envr   r:   )r#   r   r   
source_dirZinclude_argr   _r   Zerror_handlerZfile_contenterrorargrelative_pathZparent_docname	startlineendlineZsplit_on_typeZsplit_onZsplit_indexr   errtokensr   valuerN   r   Z	codeblockr   ZrsourceZ	line_funcr   r   r   r   s  s   



  



  
 
 



zMockIncludeDirective.runrj   )ro   c                 C  sL   d| j krHt| j d}d|kr*|d= |d | | jj|| dS )zAppend self.options['name'] to node['names'] if it exists.

        Also normalize the name string and register it as explicit target.
        r?   namesN)rf   r   Zfully_normalize_namer   r   r   r    Znote_explicit_target)r#   ro   r?   r   r   r   r     s    
zMockIncludeDirective.add_nameN)r   r   r   r   r-   r   r   r   r   r   r   r   X  s
    r   c                      s(   e Zd ZdZddd fddZ  ZS )MockRSTParserz.RSTParser which avoids a negative side effect.r.   znodes.document)inputstringr    c                   sH   ddl m} d}d|jkr(d}|jd }t || |rD||jd< dS )z-Parse the input to populate the document AST.r   )rolesFr\   TN)docutils.parsers.rstr   Z_rolessuperr=   )r#   r   r    r   Zshould_restoreZ	blankrole	__class__r   r   r=     s    

zMockRSTParser.parse)r   r   r   r   r=   __classcell__r   r   r   r   r     s   r   )(r   
__future__r   r   r   rG   pathlibr   typingr   r   Zdocutilsr   r   r   r   r	   Z	RSTParserZ$docutils.parsers.rst.directives.miscr
   Zdocutils.parsers.rst.statesr   r   r   Zdocutils.statemachiner   Zdocutils.utilsr   Zparsers.directivesr   r   Zmdit_to_docutils.baser   r   r   r   rL   rM   r   r   r   r   r   r   <module>   s0   ? Y" E