B
    Khh4                 @   s  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mZ ddlm	Z	m
Z
mZmZ ejdkrhddlmZ nddlmZ ddlmZ ddlmZ ed	Zed
ZedZejZejddG dd dZe eeedddZeeeef dddZeeedddZ eeee
e f dddZ!eeedddZ"eeee
e f dddZ#eeee
e f dd d!Z$ee
e ed"d#d$Z%ej&eej' d%d&d'Z(e
ej& e
e d(d)d*Z)ejddG d+d, d,Z*G d-d. d.ej+Z,ejddG d/d0 d0Z-G d1d2 d2ej+Z.dS )3z)Functions to process IPython magics with.    N)	lru_cache)DictListOptionalTuple)   
   )	TypeGuard)out)NothingChanged)zget_ipython().run_cell_magiczget_ipython().systemzget_ipython().getoutputzget_ipython().run_line_magic)	ENDMARKERNLNEWLINECOMMENTDEDENTZUNIMPORTANT_WSZ
ESCAPED_NL)captureZprunZpypypythonpython3timeZtimeitT)frozenc               @   s   e Zd ZU eed< eed< dS )ReplacementmasksrcN)__name__
__module____qualname__str__annotations__ r   r   </tmp/pip-install-vv81h98y/black/black/handle_ipynb_magics.pyr   4   s   
r   )verbosequietreturnc             C   sF   ydd l }dd l}W n( tk
r<   | s,|s8d}t| dS X dS d S )Nr   z}Skipping .ipynb files as Jupyter dependencies are not installed.
You can fix this by running ``pip install "black[jupyter]"``FT)IPythontokenize_rtModuleNotFoundErrorr
   )r    r!   r#   r$   msgr   r   r   "jupyter_dependencies_are_installed:   s    r'   )r   r"   c             C   sz   ddl m}m}m} || }d}x@||D ]4\}}|jtkr>q*|jdkr\|jdkr\||= d}P q*W |sn| dfS ||dfS )a  Remove trailing semicolon from Jupyter notebook cell.

    For example,

        fig, ax = plt.subplots()
        ax.plot(x_data, y_data);  # plot data

    would become

        fig, ax = plt.subplots()
        ax.plot(x_data, y_data)  # plot data

    Mirrors the logic in `quiet` from `IPython.core.displayhook`, but uses
    ``tokenize_rt`` so that round-tripping works fine.
    r   )reversed_enumeratesrc_to_tokenstokens_to_srcFOP;T)r$   r(   r)   r*   nameTOKENS_TO_IGNOREr   )r   r(   r)   r*   tokensZtrailing_semicolonidxtokenr   r   r   remove_trailing_semicolonK   s    
r2   )r   has_trailing_semicolonr"   c             C   st   |s| S ddl m}m}m} || }xB||D ],\}}|jtkrBq.|j|jd d||< P q.W tddt	||S )zPut trailing semicolon back if cell originally had it.

    Mirrors the logic in `quiet` from `IPython.core.displayhook`, but uses
    ``tokenize_rt`` so that round-tripping works fine.
    r   )r(   r)   r*   r,   )r   z{INTERNAL ERROR: Was not able to reinstate trailing semicolon. Please report a bug on https://github.com/psf/black/issues.  N)
r$   r(   r)   r*   r-   r.   _replacer   AssertionErrorr   )r   r3   r(   r)   r*   r/   r0   r1   r   r   r   put_trailing_semicolon_backk   s    
r6   c             C   s   g }yt |  W n tk
r&   Y n
X | |fS ddlm} | }|| }t|\}}||7 }||}t|\}}t|	 t| 	 krt
||7 }||fS )zMask IPython magics so content becomes parseable Python code.

    For example,

        %matplotlib inline
        'foo'

    becomes

        "25716f358c32750e"
        'foo'

    The replacements are returned, along with the transformed code.
    r   )TransformerManager)astparseSyntaxErrorZIPython.core.inputtransformer2r7   Ztransform_cellreplace_cell_magicsreplace_magicslen
splitlinesr   )r   replacementsr7   Ztransformer_managerZtransformedZcell_magic_replacementsZmagic_replacementsr   r   r   	mask_cell   s"    

r@   )r   magicr"   c             C   s   |st tt|d d d}t|}d}x4|| kr^t|}|d7 }|dkr,t d| dq,W t|d t|k r~| d}d| dS )	aD  Return randomly generated token to mask IPython magic with.

    For example, if 'magic' was `%matplotlib inline`, then a possible
    token to mask it with would be `"43fdd17f7e5ddc83"`. The token
    will be the same length as the magic, and we make sure that it was
    not already present anywhere else in the cell.
          r   d   zINTERNAL ERROR: Black was not able to replace IPython magic. Please report a bug on https://github.com/psf/black/issues.  The magic might be helpful: N.")r5   maxr=   	TOKEN_HEX)r   rA   nbytesr1   counterr   r   r   	get_token   s    


rK   c             C   sj   g }t | }t }|| |jdkr0| |fS |jj}t| |}|t||d | d|jj	 |fS )aN  Replace cell magic with token.

    Note that 'src' will already have been processed by IPython's
    TransformerManager().transform_cell.

    Example,

        get_ipython().run_cell_magic('t', '-n1', 'ls =!ls\n')

    becomes

        "a794."
        ls =!ls

    The replacement, along with the transformed code, is returned.
    N)r   r   
)
r8   r9   CellMagicFindervisit
cell_magicheaderrK   appendr   body)r   r?   treeZcell_magic_finderrP   r   r   r   r   r;      s    



r;   c       
      C   s   g }t  }|t|  g }xt|  ddD ]\}}||jkr|j| }t|dkrhtd| d|d j	|d j
 }}t| |}	|t|	|d |d| |	 }|| q0W d||fS )	ao  Replace magics within body of cell.

    Note that 'src' will already have been processed by IPython's
    TransformerManager().transform_cell.

    Example, this

        get_ipython().run_line_magic('matplotlib', 'inline')
        'foo'

    becomes

        "5e67db56d490fd39"
        'foo'

    The replacement, along with the transformed code, are returned.
    rC   )startz#Expecting one magic per line, got: z<
Please report a bug on https://github.com/psf/black/issues.r   )r   r   NrL   )MagicFinderrN   r8   r9   	enumerater>   magicsr=   r5   
col_offsetrA   rK   rQ   r   join)
r   r?   Zmagic_finderZnew_srcsilineZoffsets_and_magicsrX   rA   r   r   r   r   r<      s"    


r<   )r   r?   r"   c             C   s"   x|D ]}|  |j|j} qW | S )zRemove replacements from cell.

    For example

        "9b20"
        foo = bar

    becomes

        %%time
        foo = bar
    )replacer   r   )r   r?   replacementr   r   r   unmask_cell  s    
r^   )noder"   c             C   s8   t | tjo6t | jtjo6t | jjtjo6| jjjdkS )zCheck if attribute is IPython magic.

    Note that the source of the abstract syntax tree
    will already have been processed by IPython's
    TransformerManager().transform_cell.
    Zget_ipython)
isinstancer8   	AttributevalueCallfuncNameid)r_   r   r   r   _is_ipython_magic  s    rg   )argsr"   c             C   s2   g }x(| D ] }t |tjst||j q
W |S )N)r`   r8   Strr5   rQ   s)rh   Zstr_argsargr   r   r   _get_str_args.  s
    
rl   c               @   s<   e Zd ZU eed< ee ed< eed< eedddZdS )	CellMagicr-   paramsrR   )r"   c             C   s&   | j rd| j d| j  S d| j S )Nz%% )rn   r-   )selfr   r   r   rP   <  s    zCellMagic.headerN)r   r   r   r   r   r   propertyrP   r   r   r   r   rm   6  s
   
rm   c               @   s8   e Zd ZdZd	ee ddddZejddddZ	dS )
rM   a^  Find cell magics.

    Note that the source of the abstract syntax tree
    will already have been processed by IPython's
    TransformerManager().transform_cell.

    For example,

        %%time
foo()

    would have been transformed to

        get_ipython().run_cell_magic('time', '', 'foo()\n')

    and we look for instances of the latter.
    N)rO   r"   c             C   s
   || _ d S )N)rO   )rp   rO   r   r   r   __init__V  s    zCellMagicFinder.__init__)r_   r"   c             C   s^   t |jtjrPt|jjrP|jjjdkrPt|jj}t	|d |d |d d| _
| | dS )z)Find cell magic, extract header and body.Zrun_cell_magicr   rC   rB   )r-   rn   rR   N)r`   rb   r8   rc   rg   rd   attrrl   rh   rm   rO   generic_visit)rp   r_   rh   r   r   r   
visit_ExprY  s    zCellMagicFinder.visit_Expr)N)
r   r   r   __doc__r   rm   rr   r8   Exprru   r   r   r   r   rM   D  s   rM   c               @   s   e Zd ZU eed< eed< dS )OffsetAndMagicrX   rA   N)r   r   r   intr   r   r   r   r   r   rx   e  s   
rx   c               @   sB   e Zd ZdZddddZejddddZejddd	d
Z	dS )rU   a  Visit cell to look for get_ipython calls.

    Note that the source of the abstract syntax tree
    will already have been processed by IPython's
    TransformerManager().transform_cell.

    For example,

        %matplotlib inline

    would have been transformed to

        get_ipython().run_line_magic('matplotlib', 'inline')

    and we look for instances of the latter (and likewise for other
    types of magics).
    N)r"   c             C   s   t t| _d S )N)collectionsdefaultdictlistrW   )rp   r   r   r   rr     s    zMagicFinder.__init__)r_   r"   c             C   s   t |jtjrt|jjrt|jj}|jjjdkrDd|d  }nP|jjjdkr|d|d  }|d r|d|d  7 }nt	d|jjjd	d
| j
|jj t|jj| | | d
S )a{  Look for system assign magics.

        For example,

            black_version = !black --version
            env = %env var

        would have been (respectively) transformed to

            black_version = get_ipython().getoutput('black --version')
            env = get_ipython().run_line_magic('env', 'var')

        and we look for instances of any of the latter.
        	getoutput!r   run_line_magic%rC   ro   zUnexpected IPython magic zC found. Please report a bug on https://github.com/psf/black/issues.N)r`   rb   r8   rc   rg   rd   rl   rh   rs   r5   rW   linenorQ   rx   rX   rt   )rp   r_   rh   r   r   r   r   visit_Assign  s    zMagicFinder.visit_Assignc             C   s  t |jtjrt|jjrt|jj}|jjjdkr|d dkrPd|d  }q|d dkrld|d  }qd|d  }|d r|d	|d  7 }n@|jjjd
krd|d  }n"|jjjdkrd|d  }nt	| j
|jj t|jj| | | dS )a  Look for magics in body of cell.

        For examples,

            !ls
            !!ls
            ?ls
            ??ls

        would (respectively) get transformed to

            get_ipython().system('ls')
            get_ipython().getoutput('ls')
            get_ipython().run_line_magic('pinfo', 'ls')
            get_ipython().run_line_magic('pinfo2', 'ls')

        and we look for instances of any of the latter.
        r   r   Zpinfo?rC   Zpinfo2z??r   ro   systemr~   r}   z!!N)r`   rb   r8   rc   rg   rd   rl   rh   rs   r   rW   r   rQ   rx   rX   rt   )rp   r_   rh   r   r   r   r   ru     s$    zMagicFinder.visit_Expr)
r   r   r   rv   rr   r8   ZAssignr   rw   ru   r   r   r   r   rU   m  s   !rU   )/rv   r8   rz   ZdataclassesZsecretssys	functoolsr   typingr   r   r   r   version_infor	   Ztyping_extensionsZblack.outputr
   Zblack.reportr   	frozensetZTRANSFORMED_MAGICSr.   ZPYTHON_CELL_MAGICSZ	token_hexrH   Z	dataclassr   boolr'   r   r2   r6   r@   rK   r;   r<   r^   exprra   rg   rl   rm   ZNodeVisitorrM   rx   rU   r   r   r   r   <module>   sF   
		 ()!