o
   k=[?Pvp                   @   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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 )"zRefactoring 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}g }t|jD ]\}}}|dr'|r"|dd }|| q|S )zEReturn a sorted list of all available fix names in the given package.*fix_   N)
__import__pkgutilZiter_modules__path__
startswithappend)Z	fixer_pkgZremove_prefixZpkgZ	fix_namesfindernameZispkg r   6/app/.heroku/python/lib/python3.10/lib2to3/refactor.pyget_all_fix_names   s   

r   c                   @      e Zd ZdS )
_EveryNodeN__name__
__module____qualname__r   r   r   r   r   +       r   c                 C   s   t | tjtjfr| jdu rt| jhS t | tjr$| jr"t| jS tt | tj	rAt
 }| jD ]}|D ]	}|t| q4q0|S td|  )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   ZNodePatternZLeafPatterntyper   ZNegatedPatternZcontent_get_head_typesZWildcardPatternsetupdate	Exception)patrpxr   r   r   r!   /   s    


r!   c              	   C   s   t t}g }| D ];}|jr1zt|j}W n ty#   || Y q	w |D ]	}|| | q&q	|jdur?||j | q	|| q	tt	j
j t	j
jD ]	}|| | qPt|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(   

r3   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   r8   r   r8   r   get_fixers_from_packaged   s   
r;   c                 C   s   | S Nr   )objr   r   r   	_identityk   s   r>   c                    sj  d}t t| j  fdd}ttjt jtj	h}t
 }z	 | \}}||v r*q|tjkr5|r2ncd}n_|tjkr|dkr| \}}|tjksL|dkrMnR| \}}|tjks[|dkr\nH| \}}|tjkro|dkro| \}}|tjkr|| | \}}|tjks|d	krn
| \}}|tjkstnnq W t|S W t|S W t|S W t|S  ty   Y t|S w )
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_docstringrC   ignorefeaturestpvaluer   rA   r   _detect_future_featureso   s\   










rZ   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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d5ddZdd Zd5ddZdd Zd6ddZdd Zd d! Z		d7d"d#Zd8d$d%Zd&Zd'Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0d1 Zd2d3 ZdS )9RefactoringToolF)print_functionexec_functionwrite_unchanged_filesZFixr   Nc                 C   sH  || _ |pg | _| j | _|dur| j| tj | _| jd r)| jj	d= n
| jd r3| jj	d= | j
d| _g | _td| _g | _d| _tj| jtj| jd	| _|  \| _| _g | _t | _g | _g | _t| j| jD ]#}|j r~| j!| qr|| jv r| j"| qr|| jv r| j"| qrt#| j| _$t#| j| _%dS )
zInitializer.

        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.
        Nr^   printr_   execr`   r]   F)convertlogger)&fixersexplicit_default_optionscopyoptionsr#   r	   r-   grammarkeywordsgetr`   errorslogging	getLoggerrd   	fixer_logwroter   ZDriverr   rc   
get_fixers	pre_order
post_orderfilesbmZBottomMatcherBMZbmi_pre_orderZbmi_post_orderr   ZBM_compatibleZ	add_fixerr   r3   bmi_pre_order_headsbmi_post_order_heads)selfZfixer_namesri   rf   r2   r   r   r   __init__   sD   






zRefactoringTool.__init__c              	   C   sJ  g }g }| j D ]}t|i i dg}|ddd }|| jr(|t| jd }|d}| jddd	 |D  }zt	||}W n t
yQ   td
||f dw || j| j}	|	jrm| jdurm|| jvrm| d| q| d| |	jdkr~||	 q|	jdkr||	 qtd|	j 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   r5   r   N_ c                 S   s   g | ]}|  qS r   )title)r6   r'   r   r   r   r:      s    z.RefactoringTool.get_fixers.<locals>.<listcomp>zCan't find %s.%sTzSkipping optional fixer: %szAdding transformation: %spreZpostzIllegal fixer order: %rZ	run_orderkey)re   r   rsplitr   FILE_PREFIXlensplitCLASS_PREFIXjoingetattrAttributeErrorr[   ri   rp   rf   log_message	log_debugorderr   operator
attrgettersort)rz   Zpre_order_fixersZpost_order_fixersZfix_mod_pathmodr7   parts
class_nameZ	fix_classr2   Zkey_funcr   r   r   rr      s<   




zRefactoringTool.get_fixersc                  O   s    )zCalled when an error occurs.r   )rz   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)rd   inforz   r   r   r   r   r   r     s   zRefactoringTool.log_messagec                 G   s   |r|| }| j | d S r<   )rd   debugr   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   )rz   old_textnew_textfilenameequalr   r   r   print_output  s   zRefactoringTool.print_outputc                 C   s8   |D ]}t j|r| ||| q| ||| qdS )z)Refactor a list of files and directories.N)ospathisdirrefactor_dirrefactor_file)rz   itemswritedoctests_onlyZdir_or_filer   r   r   refactor  s
   zRefactoringTool.refactorc           
      C   s   t jd }t |D ]@\}}}| d| |  |  |D ]}|ds>t j|d |kr>t j||}	| 	|	|| qdd |D |dd< q
dS )zDescends 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 %sr5   r   c                 S   s   g | ]	}| d s|qS r4   )r   )r6   Zdnr   r   r   r:   2      z0RefactoringTool.refactor_dir.<locals>.<listcomp>N)
r   extsepwalkr   r   r   r   splitextr   r   )
rz   Zdir_namer   r   Zpy_extdirpathdirnames	filenamesr   fullnamer   r   r   r      s   

zRefactoringTool.refactor_dirc              
   C   s   zt |d}W n ty! } z| d|| W Y d}~dS d}~ww zt|jd }W |  n|  w tj |d|dd}| |fW  d   S 1 sPw   Y  dS )	zG
        Do our best to decode a Python source file correctly.
        rbzCan't open %s: %sNNNr   r&   r~   encodingnewline)	openOSErrorr   r   detect_encodingrK   closerI   read)rz   r   ferrr   r   r   r   _read_python_source4  s   
$z#RefactoringTool._read_python_sourcec                 C   s   |  |\}}|du rdS |d7 }|r9| d| | ||}| js&||kr1| ||||| dS | d| dS | ||}| jsG|rX|jrX| jt|dd |||d dS | 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_docstringr`   processed_filerefactor_stringwas_changedstr)rz   r   r   r   inputr   outputtreer   r   r   r   D  s    
zRefactoringTool.refactor_filec              
   C   s   t |}d|v rtj| j_z3z| j|}W n# ty9 } z| d||jj	| W Y d}~W | j| j_dS d}~ww W | j| j_n| j| j_w ||_
| 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.
        r^   zCan't parse %s: %s: %sNzRefactoring %s)rZ   r	   Z!python_grammar_no_print_statementr   rj   Zparse_stringr$   r   	__class__r   future_featuresr   refactor_tree)rz   datar   rW   r   r   r   r   r   r   [  s&   

zRefactoringTool.refactor_stringc                 C   s   t j }|r)| d | |d}| js||kr"| |d| d S | d d S | |d}| js7|rB|jrB| t	|d| d S | d d S )NzRefactoring doctests in stdinz<stdin>zNo doctest changes in stdinzNo changes in stdin)
sysstdinr   r   r   r`   r   r   r   r   )rz   r   r   r   r   r   r   r   refactor_stdinv  s   

zRefactoringTool.refactor_stdinc           
   
   C   s  t | j| jD ]}||| q| | j|  | | j|  | j|	 }t
| r| jjD ]}||v r|| r|| jtjjdd |jrV|| jtjjd t|| D ]o}||| v rk|| | zt| W n	 tyz   Y q\w |jr||jv rq\||}|r|||}|dur|| | D ]}|jsg |_|j| q| j|	 }|D ]}	|	|vrg ||	< ||	 ||	  qq\q4t
| s0t | j| jD ]}||| q|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   reverser   N)r   rs   rt   Z
start_treetraverse_byrx   ry   rw   runZleavesanyr.   re   r   r   ZBasedepthZkeep_line_orderZ
get_linenor+   remover   
ValueErrorZfixers_appliedmatch	transformreplacer   r0   Zfinish_treer   )
rz   r   r   r2   Z	match_setnoderesultsnewZnew_matchesZfxrr   r   r   r     sP   

1zRefactoringTool.refactor_treec                 C   sV   |sdS |D ]"}||j  D ]}||}|r'|||}|dur'|| |}qq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   )rz   re   Z	traversalr   r2   r   r   r   r   r   r     s   

zRefactoringTool.traverse_byc                 C   s   | j | |du r| |d }|du rdS ||k}| |||| |r0| d| | js0dS |r<| |||| dS | 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)ru   r   r   r   r   r`   
write_file)rz   r   r   r   r   r   r   r   r   r   r     s   zRefactoringTool.processed_filec                 C   s   zt j|d|dd}W n ty% } z| d|| W Y d}~dS d}~ww |) z|| W n tyI } z| d|| W Y d}~nd}~ww W d   n1 sTw   Y  | d| d| _dS )	zWrites 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   zCan't create %s: %sNzCan't write %s: %szWrote changes to %sT)rI   r   r   r   r   r   rq   )rz   r   r   r   r   fpr   r   r   r   r     s$   
zRefactoringTool.write_filez>>> z... c           
   	   C   s  g }d}d}d}d}|j ddD ]d}|d7 }| | jr?|dur-|| |||| |}|g}|| j}	|d|	 }q|dur\||| j sV||| j  d kr\|	| q|durk|| |||| d}d}|	| q|du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   PS1r0   refactor_doctestfindPS2rstripr   r   )
rz   r   r   resultblockZblock_linenoindentlinenolineir   r   r   r     sD   
z"RefactoringTool.refactor_docstringc           
   
      s(  z	 || }W n4 ty= } z(jtjr&|D ]}d|d qd|||j	j
| |W  Y d}~S d}~ww ||rt|jdd}|d|d  ||d d }	}|	dg|d  ksjJ |	|d dsy|d  d7  <  j |d	 g}|r| fd
d|D 7 }|S )zRefactors 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: %sNTr   r   r|   r   c                    s   g | ]	} j  | qS r   )r   )r6   r   r   rz   r   r   r:   ^  r   z4RefactoringTool.refactor_doctest.<locals>.<listcomp>)parse_blockr$   rd   isEnabledForrn   DEBUGr   r   r   r   r   r   r   r   endswithr   pop)
rz   r   r   r   r   r   r   r   r   Zclippedr   r   r   r   D  s,   "z RefactoringTool.refactor_doctestc                 C   s   | j rd}nd}| js| d| n| d| | jD ]}| | q| jr6| d | jD ]}| | q.| jrdt| jdkrF| d n	| dt| j | jD ]\}}}| j|g|R i | qRd S 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:)rq   ru   r   rp   rm   r   )rz   r   filemessager   r   r   r   r   r   	summarizea  s(   


zRefactoringTool.summarizec                 C   s"   | j | |||}t |_|S )zParses 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_toksrL   r   )rz   r   r   r   r   r   r   r   r   x  s   zRefactoringTool.parse_blockc                 c   sf    t | ||j}|D ]#\}}\}}\}	}
}||d 7 }|	|d 7 }	||||f|	|
f|fV  qdS )z;Wraps a tokenize stream to systematically modify start/end.r   N)r   rH   	gen_lines__next__)rz   r   r   r   r/   r    rY   Zline0Zcol0Zline1Zcol1Z	line_textr   r   r   r     s   zRefactoringTool.wrap_toksc                 c   sx    || j  }|| j }|}|D ]'}||r |t|d V  n|| d kr,dV  ntd||f |}q	 dV  q8)zGenerates 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=%rTr~   )r   r   r   r   r   AssertionError)rz   r   r   prefix1Zprefix2prefixr   r   r   r   r     s   


zRefactoringTool.gen_linesr   )FF)F)NFNr<   )r   r   r   rg   r   r   r{   rr   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   r]      sB    
7(

	

O

+
r]   c                   @   r   )MultiprocessingUnsupportedNr   r   r   r   r   r     r   r   c                       sF   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|i | d | _d | _d S r<   )superr   r{   queueoutput_lockrz   r   kwargsr   r   r   r{     s   
z$MultiprocessRefactoringTool.__init__Fr   c              
      s2  |dkrt t|||S zdd l W n	 ty   tw jd ur'td  _ 	 _
 fddt|D }z8|D ]}|  q@t t||| W j  t|D ]}jd  q[|D ]
}| rp|  qfd _d S j  t|D ]}jd  q|D ]
}| r|  qd _w )Nr   r   z already doing multiple processesc                    s   g | ]	} j jd qS ))target)Process_child)r6   r   multiprocessingrz   r   r   r:     s    z8MultiprocessRefactoringTool.refactor.<locals>.<listcomp>)r   r   r   r
  ImportErrorr   r  RuntimeErrorJoinableQueueLockr  rangestartr   putis_alive)rz   r   r   r   Znum_processes	processesr'   r   r  r	  r   r     sL   







z$MultiprocessRefactoringTool.refactorc                    sf   | j  }|d ur1|\}}ztt| j|i | W | j   n| j   w | j  }|d us	d S d S r<   )r  rl   r   r   r   	task_done)rz   Ztaskr   r  r  r   r   r    s   


z"MultiprocessRefactoringTool._childc                    s4   | j d ur| j ||f d S tt| j|i |S 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)#r\   
__author__rI   r   r   r   rn   r   r)   	itertoolsr   Zpgen2r   r   r   Z
fixer_utilr   r~   r   r	   r
   rv   r   r$   r   r!   r3   r;   r>   rZ   r[   objectr]   r   r   r   r   r   r   <module>   s:   
(    