B
    18™\0k  ã               @   s  d Z 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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mZ dd	lmZ d!dd„ZG dd„ deƒZdd„ Zdd„ Zdd„ Zdd„ Zdd„ ZG dd„ deƒZG dd„ deƒZG dd„ deƒZ G dd „ d eƒZ!dS )"zÛRefactoring framework.

Used as a main program, this can refactor any number of files and/or
recursively descend down directories.  Imported as a module, this
provides infrastructure to write your own refactoring tool.
z#Guido van Rossum <guido@python.org>é    N)Úchainé   )ÚdriverÚtokenizeÚtoken)Ú	find_root)ÚpytreeÚpygram)Úbtm_matcherTc             C   st   t | g g dgƒ}tj |j¡}g }xLtt |¡ƒD ]:}| d¡r2| d¡r2|rZ|dd… }| 	|dd… ¡ q2W |S )zEReturn a sorted list of all available fix names in the given package.Ú*Úfix_z.pyé   Néýÿÿÿ)
Ú
__import__ÚosÚpathÚdirnameÚ__file__ÚsortedÚlistdirÚ
startswithÚendswithÚappend)Ú	fixer_pkgZremove_prefixÚpkgZ	fixer_dirZ	fix_namesÚname© r   úT/oak/stanford/groups/akundaje/marinovg/programs/Python-3.7.3/Lib/lib2to3/refactor.pyÚget_all_fix_names   s    r   c               @   s   e Zd ZdS )Ú
_EveryNodeN)Ú__name__Ú
__module__Ú__qualname__r   r   r   r   r   +   s   r   c             C   sš   t | tjtjfƒr(| jdkr t‚| jhS t | tjƒrH| jrDt| jƒS t‚t | tj	ƒrŠt
ƒ }x*| jD ] }x|D ]}| t|ƒ¡ qlW qbW |S td|  ƒ‚dS )zf Accepts a pytree Pattern Node and returns a set
        of the pattern types which will match first. Nz$Oh no! I don't understand pattern %s)Ú
isinstancer   ÚNodePatternÚLeafPatternÚtyper   ÚNegatedPatternÚcontentÚ_get_head_typesÚWildcardPatternÚsetÚupdateÚ	Exception)ÚpatÚrÚpÚxr   r   r   r)   /   s    


r)   c          	   C   sÊ   t  t¡}g }x„| D ]|}|jrjyt|jƒ}W n tk
rJ   | |¡ Y qX xB|D ]}||  |¡ qRW q|jdk	r†||j  |¡ q| |¡ qW x,tt	j
j ¡ t	j
jƒD ]}||  |¡ q¬W t|ƒS )z^ Accepts a list of fixers and returns a dictionary
        of head node type --> fixer list.  N)ÚcollectionsÚdefaultdictÚlistÚpatternr)   r   r   Z_accept_typer   r	   Úpython_grammarZsymbol2numberÚvaluesÚtokensÚextendÚdict)Z
fixer_listZ
head_nodesZeveryÚfixerZheadsZ	node_typer   r   r   Ú_get_headnode_dictK   s"    



r<   c                s   ‡ fdd„t ˆ dƒD ƒS )zN
    Return the fully qualified names for fixers in the package pkg_name.
    c                s   g | ]}ˆ d  | ‘qS )Ú.r   )Ú.0Úfix_name)Úpkg_namer   r   ú
<listcomp>h   s   z+get_fixers_from_package.<locals>.<listcomp>F)r   )r@   r   )r@   r   Úget_fixers_from_packaged   s    
rB   c             C   s   | S )Nr   )Úobjr   r   r   Ú	_identityk   s    rD   c                sV  d}t  t | ¡j¡‰ ‡ fdd„}ttjt jtj	hƒ}t
ƒ }yúxô|ƒ \}}||krVq@q@|tjkrl|rfP d}q@|tjkr.|dkr.|ƒ \}}|tjksž|dkr P |ƒ \}}|tjks¼|dkr¾P |ƒ \}}|tjkrä|dkrä|ƒ \}}xJ|tjkr*| |¡ |ƒ \}}|tjks|d	krP |ƒ \}}qæW q@P q@W W n tk
rL   Y nX t|ƒS )
NFc                 s   t ˆ ƒ} | d | d fS )Nr   r   )Únext)Útok)Úgenr   r   Úadvancer   s    z(_detect_future_features.<locals>.advanceTÚfromZ
__future__Úimportú(ú,)r   Úgenerate_tokensÚioÚStringIOÚreadlineÚ	frozensetr   ÚNEWLINEÚNLÚCOMMENTr+   ÚSTRINGÚNAMEÚOPÚaddÚStopIteration)ÚsourceZhave_docstringrH   ÚignoreÚfeaturesÚtpÚvaluer   )rG   r   Ú_detect_future_featureso   sD    








r_   c               @   s   e Zd ZdZdS )Ú
FixerErrorzA fixer could not be loaded.N)r    r!   r"   Ú__doc__r   r   r   r   r`   —   s   r`   c               @   sä   e Zd ZdddœZdZdZd4dd„Zdd	„ Zd
d„ Zdd„ Z	dd„ Z
dd„ Zd5dd„Zd6dd„Zdd„ Zd7dd„Zdd„ Zd8dd„Zdd„ Zd d!„ Zd9d"d#„Zd:d$d%„Zd&Zd'Zd(d)„ Zd*d+„ Zd,d-„ Zd.d/„ Zd0d1„ Zd2d3„ ZdS );ÚRefactoringToolF)Úprint_functionÚwrite_unchanged_filesZFixr   Nc             C   s2  || _ |pg | _| j ¡ | _|dk	r0| j |¡ | jd rDtj| _ntj	| _| j 
d¡| _g | _t d¡| _g | _d| _tj| jtj| jd| _|  ¡ \| _| _g | _t ¡ | _g | _g | _xXt| j| jƒD ]F}|j rä| j !|¡ qÌ|| jkrü| j "|¡ qÌ|| jkrÌ| j "|¡ qÌW t#| jƒ| _$t#| jƒ| _%dS )zÑInitializer.

        Args:
            fixer_names: a list of fixers to import
            options: a dict with configuration.
            explicit: a list of fixers to run even if they are explicit.
        Nrc   rd   rb   F)ÚconvertÚlogger)&ÚfixersÚexplicitÚ_default_optionsÚcopyÚoptionsr,   r	   Ú!python_grammar_no_print_statementÚgrammarr6   Úgetrd   ÚerrorsÚloggingÚ	getLoggerrf   Ú	fixer_logÚwroter   ÚDriverr   re   Ú
get_fixersÚ	pre_orderÚ
post_orderÚfilesÚbmZBottomMatcherÚBMZbmi_pre_orderZbmi_post_orderr   ZBM_compatibleZ	add_fixerr   r<   Úbmi_pre_order_headsÚbmi_post_order_heads)ÚselfZfixer_namesrk   rh   r;   r   r   r   Ú__init__£   s<    





zRefactoringTool.__init__c          	   C   s^  g }g }x(| j D ]}t|i i dgƒ}| dd¡d }| | j¡rV|t| jƒd… }| d¡}| jd dd	„ |D ƒ¡ }yt	||ƒ}W n& t
k
r®   td
||f ƒd‚Y nX || j| jƒ}	|	jræ| jdk	ræ|| jkræ|  d|¡ q|  d|¡ |	jdkr
| |	¡ q|	jdkr"| |	¡ qtd|	j ƒ‚qW t d¡}
|j|
d |j|
d ||fS )a  Inspects the options to load the requested patterns and handlers.

        Returns:
          (pre_order, post_order), where pre_order is the list of fixers that
          want a pre-order AST traversal, and post_order is the list that want
          post-order traversal.
        r   r=   r   éÿÿÿÿNÚ_Ú c             S   s   g | ]}|  ¡ ‘qS r   )Útitle)r>   r0   r   r   r   rA   ç   s    z.RefactoringTool.get_fixers.<locals>.<listcomp>zCan't find %s.%sTzSkipping optional fixer: %szAdding transformation: %sÚpreÚpostzIllegal fixer order: %rZ	run_order)Úkey)rg   r   Úrsplitr   ÚFILE_PREFIXÚlenÚsplitÚCLASS_PREFIXÚjoinÚgetattrÚAttributeErrorr`   rk   rr   rh   Úlog_messageÚ	log_debugÚorderr   ÚoperatorÚ
attrgetterÚsort)r}   Zpre_order_fixersZpost_order_fixersZfix_mod_pathÚmodr?   ÚpartsÚ
class_nameZ	fix_classr;   Zkey_funcr   r   r   ru   ×   s8    


zRefactoringTool.get_fixersc              O   s   ‚ dS )zCalled when an error occurs.Nr   )r}   ÚmsgÚargsÚkwdsr   r   r   Ú	log_errorÿ   s    zRefactoringTool.log_errorc             G   s   |r|| }| j  |¡ dS )zHook to log a message.N)rf   Úinfo)r}   r—   r˜   r   r   r   rŽ     s    zRefactoringTool.log_messagec             G   s   |r|| }| j  |¡ d S )N)rf   Údebug)r}   r—   r˜   r   r   r   r   	  s    zRefactoringTool.log_debugc             C   s   dS )zTCalled with the old version, new version, and filename of a
        refactored file.Nr   )r}   Úold_textÚnew_textÚfilenameÚequalr   r   r   Úprint_output  s    zRefactoringTool.print_outputc             C   s<   x6|D ].}t j |¡r&|  |||¡ q|  |||¡ qW dS )z)Refactor a list of files and directories.N)r   r   ÚisdirÚrefactor_dirÚrefactor_file)r}   ÚitemsÚwriteÚdoctests_onlyZdir_or_filer   r   r   Úrefactor  s    
zRefactoringTool.refactorc       
      C   s¢   t jd }x’t  |¡D ]„\}}}|  d|¡ | ¡  | ¡  xF|D ]>}| d¡sBt j |¡d |krBt j ||¡}	|  	|	||¡ qBW dd„ |D ƒ|dd…< qW dS )zÄDescends down a directory and refactor every Python file found.

        Python files are assumed to have a .py extension.

        Files and subdirectories starting with '.' are skipped.
        ÚpyzDescending into %sr=   r   c             S   s   g | ]}|  d ¡s|‘qS )r=   )r   )r>   Údnr   r   r   rA   .  s    z0RefactoringTool.refactor_dir.<locals>.<listcomp>N)
r   ÚextsepÚwalkr   r“   r   r   Úsplitextr‹   r¤   )
r}   Zdir_namer¦   r§   Zpy_extÚdirpathÚdirnamesÚ	filenamesr   Úfullnamer   r   r   r£     s    


zRefactoringTool.refactor_dirc          
   C   sŠ   yt |dƒ}W n0 tk
r> } z|  d||¡ dS d}~X Y nX zt |j¡d }W d| ¡  X tj |d|dd}| ¡ |fS Q R X dS )	zG
        Do our best to decode a Python source file correctly.
        ÚrbzCan't open %s: %s)NNNr   r/   r   )ÚencodingÚnewline)	ÚopenÚOSErrorrš   r   Údetect_encodingrP   ÚcloserN   Úread)r}   rŸ   ÚfÚerrr³   r   r   r   Ú_read_python_source0  s    
z#RefactoringTool._read_python_sourcec             C   sº   |   |¡\}}|dkrdS |d7 }|rn|  d|¡ |  ||¡}| jsL||kr`|  |||||¡ q¶|  d|¡ nH|  ||¡}| jsŠ|rª|jrª| jt|ƒdd… |||d n|  d|¡ dS )zRefactors a file.NÚ
zRefactoring doctests in %szNo doctest changes in %sr   )r¦   r³   zNo changes in %s)r¼   r   Úrefactor_docstringrd   Úprocessed_fileÚrefactor_stringÚwas_changedÚstr)r}   rŸ   r¦   r§   Úinputr³   ÚoutputÚtreer   r   r   r¤   @  s    zRefactoringTool.refactor_filec          
   C   s–   t |ƒ}d|krtj| j_zLy| j |¡}W n6 tk
rb } z|  d||jj	|¡ dS d}~X Y nX W d| j| j_X ||_
|  d|¡ |  ||¡ |S )aF  Refactor a given input string.

        Args:
            data: a string holding the code to be refactored.
            name: a human-readable name for use in error/log messages.

        Returns:
            An AST corresponding to the refactored input stream; None if
            there were errors during the parse.
        rc   zCan't parse %s: %s: %sNzRefactoring %s)r_   r	   rl   r   rm   Úparse_stringr-   rš   Ú	__class__r    Úfuture_featuresr   Úrefactor_tree)r}   Údatar   r\   rÅ   r»   r   r   r   rÀ   W  s    
zRefactoringTool.refactor_stringc             C   sŒ   t j ¡ }|rN|  d¡ |  |d¡}| js2||krB|  |d|¡ qˆ|  d¡ n:|  |d¡}| jsj|r~|jr~|  t	|ƒd|¡ n
|  d¡ d S )NzRefactoring doctests in stdinz<stdin>zNo doctest changes in stdinzNo changes in stdin)
ÚsysÚstdinr¹   r   r¾   rd   r¿   rÀ   rÁ   rÂ   )r}   r§   rÃ   rÄ   rÅ   r   r   r   Úrefactor_stdinr  s    

zRefactoringTool.refactor_stdinc       
   
   C   sü  x"t | j| jƒD ]}| ||¡ qW |  | j| ¡ ¡ |  | j| ¡ ¡ | j | 	¡ ¡}xtt
| ¡ ƒrÎx^| jjD ]P}||krv|| rv|| jtjjdd |jr¼|| jtjjd xt|| ƒD ]ø}||| krê||  |¡ yt|ƒ W n tk
r   wÌY nX |jr&||jkr&qÌ| |¡}|rÌ| ||¡}|dk	rÌ| |¡ x,| ¡ D ] }|jsng |_|j |¡ q\W | j | 	¡ ¡}x2|D ]*}	|	|kr¬g ||	< ||	  ||	 ¡ q–W qÌW qvW q\W x$t | j| jƒD ]}| ||¡ qàW |jS )aÏ  Refactors a parse tree (modifying the tree in place).

        For compatible patterns the bottom matcher module is
        used. Otherwise the tree is traversed node-to-node for
        matches.

        Args:
            tree: a pytree.Node instance representing the root of the tree
                  to be refactored.
            name: a human-readable name for this tree.

        Returns:
            True if the tree was modified, False otherwise.
        T)r…   Úreverse)r…   N)r   rv   rw   Z
start_treeÚtraverse_byr{   r|   rz   ÚrunÚleavesÚanyr7   rg   r“   r   ÚBaseÚdepthZkeep_line_orderÚ
get_linenor4   Úremover   Ú
ValueErrorÚfixers_appliedÚmatchÚ	transformÚreplacer   r9   Zfinish_treerÁ   )
r}   rÅ   r   r;   Z	match_setÚnodeÚresultsÚnewZnew_matchesZfxrr   r   r   rÉ   ‚  sJ    



$zRefactoringTool.refactor_treec             C   s^   |sdS xP|D ]H}xB||j  D ]4}| |¡}|r| ||¡}|dk	r| |¡ |}qW qW dS )a  Traverse an AST, applying a set of fixers to each node.

        This is a helper method for refactor_tree().

        Args:
            fixers: a list of fixer instances.
            traversal: a generator that yields AST nodes.

        Returns:
            None
        N)r&   rÙ   rÚ   rÛ   )r}   rg   Z	traversalrÜ   r;   rÝ   rÞ   r   r   r   rÏ   Ñ  s    


zRefactoringTool.traverse_byc             C   s†   | j  |¡ |dkr.|  |¡d }|dkr.dS ||k}|  ||||¡ |r`|  d|¡ | js`dS |rv|  ||||¡ n|  d|¡ dS )zR
        Called when a file has been refactored and there may be changes.
        Nr   zNo changes to %szNot writing changes to %s)rx   r   r¼   r¡   r   rd   Ú
write_file)r}   rž   rŸ   r   r¦   r³   r    r   r   r   r¿   è  s    zRefactoringTool.processed_filec             C   s®   yt j|d|dd}W n0 tk
rF } z|  d||¡ dS d}~X Y nX |F y| |¡ W n0 tk
rŒ } z|  d||¡ W dd}~X Y nX W dQ R X |  d|¡ d| _dS )	zÑWrites a string to a file.

        It first shows a unified diff between the old text and the new text, and
        then rewrites the file; the latter is only done if the write option is
        set.
        Úwr   )r³   r´   zCan't create %s: %sNzCan't write %s: %szWrote changes to %sT)rN   rµ   r¶   rš   r¦   r   rs   )r}   rž   rŸ   r   r³   Úfpr»   r   r   r   rß   ý  s    *zRefactoringTool.write_filez>>> z... c       
   	   C   s  g }d}d}d}d}xØ|j ddD ]È}|d7 }| ¡  | j¡r€|dk	r\| |  ||||¡¡ |}|g}| | j¡}	|d|	… }q"|dk	rº| || j ¡s®||| j ¡  d krº| 	|¡ q"|dk	rØ| |  ||||¡¡ d}d}| 	|¡ q"W |dk	r| |  ||||¡¡ d 
|¡S )aË  Refactors a docstring, looking for doctests.

        This returns a modified version of the input string.  It looks
        for doctests, which start with a ">>>" prompt, and may be
        continued with "..." prompts, as long as the "..." is indented
        the same as the ">>>".

        (Unfortunately we can't use the doctest module's parser,
        since, like most parsers, it is not geared towards preserving
        the original source.)
        Nr   T)Úkeependsr   r½   r   )Ú
splitlinesÚlstripr   ÚPS1r9   Úrefactor_doctestÚfindÚPS2Úrstripr   r‹   )
r}   rÃ   rŸ   ÚresultÚblockZblock_linenoÚindentÚlinenoÚlineÚir   r   r   r¾     s:    



z"RefactoringTool.refactor_docstringc       
   
      s*  yˆ  ||ˆ ¡}W nf tk
rx } zHˆj tj¡rRx|D ]}ˆ d| d¡¡ q8W ˆ d|||j	j
|¡ |S d}~X Y nX ˆ ||¡r&t|ƒjdd}|d|d … ||d d…  }	}|	dg|d  ksÔt|	ƒ‚|d  d¡sò|d  d7  < ˆ ˆj | d	¡ g}|r&|‡ ‡fd
d„|D ƒ7 }|S )zÞRefactors one doctest.

        A doctest is given as a block of lines, the first of which starts
        with ">>>" (possibly indented), while the remaining lines start
        with "..." (identically indented).

        z
Source: %sr½   z+Can't parse docstring in %s line %s: %s: %sNT)râ   r   r   r   c                s   g | ]}ˆ ˆj  | ‘qS r   )rè   )r>   rî   )rì   r}   r   r   rA   Z  s    z4RefactoringTool.refactor_doctest.<locals>.<listcomp>)Úparse_blockr-   rf   ÚisEnabledForrp   ÚDEBUGr   ré   rš   rÇ   r    rÉ   rÂ   rã   ÚAssertionErrorr   rå   Úpop)
r}   rë   rí   rì   rŸ   rÅ   r»   rî   rÞ   Zclippedr   )rì   r}   r   ræ   @  s&    
"z RefactoringTool.refactor_doctestc             C   sÒ   | j rd}nd}| js$|  d|¡ n&|  d|¡ x| jD ]}|  |¡ q8W | jrt|  d¡ x| jD ]}|  |¡ qbW | jrÎt| jƒdkr”|  d¡ n|  dt| jƒ¡ x&| jD ]\}}}| j|f|ž|Ž q®W d S )	NÚwerez
need to bezNo files %s modified.zFiles that %s modified:z$Warnings/messages while refactoring:r   zThere was 1 error:zThere were %d errors:)rs   rx   rŽ   rr   ro   rˆ   )r}   rõ   ÚfileÚmessager—   r˜   r™   r   r   r   Ú	summarize]  s$    
zRefactoringTool.summarizec             C   s"   | j  |  |||¡¡}tƒ |_|S )z³Parses a block into a tree.

        This is necessary to get correct line number / offset information
        in the parser diagnostics and embedded into the parse tree.
        )r   Zparse_tokensÚ	wrap_toksrQ   rÈ   )r}   rë   rí   rì   rÅ   r   r   r   rð   t  s    zRefactoringTool.parse_blockc             c   sh   t  |  ||¡j¡}xN|D ]F\}}\}}\}	}
}||d 7 }|	|d 7 }	||||f|	|
f|fV  qW dS )z;Wraps a tokenize stream to systematically modify start/end.r   N)r   rM   Ú	gen_linesÚ__next__)r}   rë   rí   rì   r8   r&   r^   Zline0Zcol0Úline1Zcol1Z	line_textr   r   r   rù   ~  s
    zRefactoringTool.wrap_toksc             c   s€   || j  }|| j }|}xV|D ]N}| |¡r@|t|ƒd… V  n(|| ¡ d krXdV  ntd||f ƒ‚|}qW x
dV  qrW dS )z–Generates lines as expected by tokenize from a list of lines.

        This strips the first len(indent + self.PS1) characters off each line.
        Nr½   zline=%r, prefix=%rr   )rå   rè   r   rˆ   ré   ró   )r}   rë   rì   Úprefix1Zprefix2Úprefixrî   r   r   r   rú   Œ  s    



zRefactoringTool.gen_lines)NN)FF)FF)FF)F)NFN)N)r    r!   r"   ri   rŠ   r‡   r~   ru   rš   rŽ   r   r¡   r¨   r£   r¼   r¤   rÀ   rÍ   rÉ   rÏ   r¿   rß   rå   rè   r¾   ræ   rø   rð   rù   rú   r   r   r   r   rb   ›   s:   
4(
	


O 

+
rb   c               @   s   e Zd ZdS )ÚMultiprocessingUnsupportedN)r    r!   r"   r   r   r   r   rÿ      s   rÿ   c                   sB   e Zd Z‡ fdd„Zd‡ fdd„	Z‡ fdd„Z‡ fd	d
„Z‡  ZS )ÚMultiprocessRefactoringToolc                s"   t t| ƒj||Ž d | _d | _d S )N)Úsuperr   r~   ÚqueueÚoutput_lock)r}   r˜   Úkwargs)rÇ   r   r   r~   ¦  s    z$MultiprocessRefactoringTool.__init__Fr   c          
      s  |dkrt tˆƒ |||¡S ydd l‰ W n tk
r@   t‚Y nX ˆjd k	rTtdƒ‚ˆ  ¡ ˆ_ˆ  	¡ ˆ_
‡ ‡fdd„t|ƒD ƒ}z.x|D ]}| ¡  qˆW t tˆƒ |||¡ W d ˆj ¡  xt|ƒD ]}ˆj d ¡ qÄW x|D ]}| ¡ rÞ| ¡  qÞW d ˆ_X d S )Nr   r   z already doing multiple processesc                s   g | ]}ˆ j ˆjd ‘qS ))Útarget)ÚProcessÚ_child)r>   rï   )Úmultiprocessingr}   r   r   rA   ¸  s   z8MultiprocessRefactoringTool.refactor.<locals>.<listcomp>)r  r   r¨   r  ÚImportErrorrÿ   r  ÚRuntimeErrorÚJoinableQueueÚLockr  ÚrangeÚstartr‹   ÚputÚis_alive)r}   r¥   r¦   r§   Znum_processesÚ	processesr0   rï   )rÇ   )r  r}   r   r¨   «  s2    









z$MultiprocessRefactoringTool.refactorc                sR   | j  ¡ }xB|d k	rL|\}}ztt| ƒj||Ž W d | j  ¡  X | j  ¡ }qW d S )N)r  rn   r  r   r¤   Ú	task_done)r}   Ztaskr˜   r  )rÇ   r   r   r  È  s    


z"MultiprocessRefactoringTool._childc                s2   | j d k	r| j  ||f¡ ntt| ƒj||ŽS d S )N)r  r  r  r   r¤   )r}   r˜   r  )rÇ   r   r   r¤   Ó  s    

z)MultiprocessRefactoringTool.refactor_file)FFr   )r    r!   r"   r~   r¨   r  r¤   Ú__classcell__r   r   )rÇ   r   r   ¤  s
    r   )T)"ra   Ú
__author__rN   r   rË   rp   r‘   r2   Ú	itertoolsr   Zpgen2r   r   r   Z
fixer_utilr   r   r   r	   r
   ry   r   r-   r   r)   r<   rB   rD   r_   r`   Úobjectrb   rÿ   r   r   r   r   r   Ú<module>	   s6   
(    	