B ;Ôð‰'B¢Sã@sdZdZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z m Z mZddlmZddlmZmZdd lmZd!d d „ZGd d„deƒZdd„Zdd„Zdd„Zdd„Zdd„ZGdd„deƒZGdd„deƒZ Gdd„deƒZ!Gdd „d e ƒZ"dS)"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 éN)Úchainé)ÚdriverÚtokenizeÚtoken)Ú find_root)ÚpytreeÚpygram)Ú btm_matcherTcCsXt|ggdgƒ}g}x>t |j¡D].\}}}| d¡r"|rF|dd…}| |¡q"W|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_prefixZpkgZ fix_namesÚfinderÚnameZispkg©rú5/opt/alt/python37/lib64/python3.7/lib2to3/refactor.pyÚget_all_fix_namess  rc@s eZdZdS)Ú _EveryNodeN)Ú__name__Ú __module__Ú __qualname__rrrrr+srcCsšt|tjtjfƒr(|jdkr t‚|jhSt|tjƒrH|jrDt|jƒSt‚t|tj ƒrŠt ƒ}x*|jD] }x|D]}|  t|ƒ¡qlWqbW|St d|ƒ‚dS)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) Ú isinstancerZ NodePatternZ LeafPatternÚtyperZNegatedPatternZcontentÚ_get_head_typesZWildcardPatternÚsetÚupdateÚ Exception)ZpatÚrÚpÚxrrrr/s      rc CsÊt t¡}g}x„|D]|}|jrjyt|jƒ}Wntk rJ| |¡YqXxB|D]}|| |¡qRWq|jdk r†||j |¡q| |¡qWx,tt j j   ¡t j j ƒD]}|| |¡q¬Wt|ƒS)z^ Accepts a list of fixers and returns a dictionary of head node type --> fixer list. N)Ú collectionsÚ defaultdictÚlistÚpatternrrrZ _accept_typerr Úpython_grammarZ symbol2numberÚvaluesÚtokensÚextendÚdict)Z fixer_listZ head_nodesZeveryÚfixerZheadsZ node_typerrrÚ_get_headnode_dictKs"    r/cs‡fdd„tˆdƒDƒS)zN Return the fully qualified names for fixers in the package pkg_name. csg|]}ˆd|‘qS)Ú.r)Ú.0Úfix_name)Úpkg_namerrú hsz+get_fixers_from_package..F)r)r3r)r3rÚget_fixers_from_packageds r5cCs|S)Nr)ÚobjrrrÚ _identityksr7csVd}t t |¡j¡‰‡fdd„}ttjtjtj hƒ}t ƒ}yúxô|ƒ\}}||krVq@q@|tj krl|rfPd}q@|tj kr.|dkr.|ƒ\}}|tj ksž|dkr P|ƒ\}}|tj ks¼|dkr¾P|ƒ\}}|tj krä|dkrä|ƒ\}}xJ|tj kr*| |¡|ƒ\}}|tj ks|d krP|ƒ\}}qæWq@Pq@WWntk rLYnXt|ƒS) NFcstˆƒ}|d|dfS)Nrr)Únext)Útok)ÚgenrrÚadvancersz(_detect_future_features..advanceTÚfromZ __future__Úimportú(ú,)rÚgenerate_tokensÚioÚStringIOÚreadlineÚ frozensetrÚNEWLINEÚNLÚCOMMENTrÚSTRINGÚNAMEÚOPÚaddÚ StopIteration)ÚsourceZhave_docstringr;ÚignoreÚfeaturesÚtpÚvaluer)r:rÚ_detect_future_featuresosD          rRc@seZdZdZdS)Ú FixerErrorzA fixer could not be loaded.N)rrrÚ__doc__rrrrrS—srSc@säeZdZdddœZdZdZd4dd„Zdd „Zd d „Zd d „Z dd„Z dd„Z d5dd„Z d6dd„Z dd„Zd7dd„Zdd„Zd8dd„Zdd„Zd d!„Zd9d"d#„Zd:d$d%„Zd&Zd'Zd(d)„Zd*d+„Zd,d-„Zd.d/„Zd0d1„Zd2d3„ZdS);ÚRefactoringToolF)Úprint_functionÚwrite_unchanged_filesZFixr NcCs2||_|p g|_|j ¡|_|dk r0|j |¡|jdrDtj|_ntj |_|j  d¡|_ g|_ t  d¡|_g|_d|_tj|jtj|jd|_| ¡\|_|_g|_t ¡|_g|_g|_xXt|j|jƒD]F}|j rä|j !|¡qÌ||jkrü|j "|¡qÌ||jkrÌ|j "|¡qÌWt#|jƒ|_$t#|jƒ|_%dS)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. NrVrWrUF)ÚconvertÚlogger)&ÚfixersÚexplicitÚ_default_optionsÚcopyÚoptionsr r Ú!python_grammar_no_print_statementÚgrammarr)ÚgetrWÚerrorsÚloggingZ getLoggerrYÚ fixer_logÚwroterZDriverrrXÚ get_fixersÚ pre_orderÚ post_orderÚfilesÚbmZ BottomMatcherÚBMZ bmi_pre_orderZbmi_post_orderrZ BM_compatibleZ add_fixerrr/Úbmi_pre_order_headsÚbmi_post_order_heads)ÚselfZ fixer_namesr^r[r.rrrÚ__init__£s<           zRefactoringTool.__init__c Cs^g}g}x(|jD]}t|iidgƒ}| dd¡d}| |j¡rV|t|jƒd…}| d¡}|jd dd „|Dƒ¡}yt ||ƒ}Wn&t k r®t d ||fƒd‚YnX||j |j ƒ} | jræ|jd k ræ||jkræ| d |¡q| d |¡| jdkr | | ¡q| jdkr"| | ¡qt d| jƒ‚qWt d¡} |j| d|j| d||fS)aInspects 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 r0réÿÿÿÿNÚ_ÚcSsg|] }| ¡‘qSr)Útitle)r1r#rrrr4çsz.RefactoringTool.get_fixers..zCan't find %s.%sTzSkipping optional fixer: %szAdding transformation: %sZpreZpostzIllegal fixer order: %rZ run_order)Úkey)rZrÚrsplitrÚ FILE_PREFIXÚlenÚsplitÚ CLASS_PREFIXÚjoinÚgetattrÚAttributeErrorrSr^rdr[Ú log_messageÚ log_debugÚorderrÚoperatorÚ attrgetterÚsort) rnZpre_order_fixersZpost_order_fixersZ fix_mod_pathÚmodr2ÚpartsÚ class_nameZ fix_classr.Zkey_funcrrrrf×s8            zRefactoringTool.get_fixerscOs‚dS)zCalled when an error occurs.Nr)rnÚmsgÚargsÚkwdsrrrÚ log_errorÿszRefactoringTool.log_errorcGs|r ||}|j |¡dS)zHook to log a message.N)rYÚinfo)rnr†r‡rrrr}szRefactoringTool.log_messagecGs|r ||}|j |¡dS)N)rYÚdebug)rnr†r‡rrrr~ szRefactoringTool.log_debugcCsdS)zTCalled with the old version, new version, and filename of a refactored file.Nr)rnÚold_textÚnew_textÚfilenameÚequalrrrÚ print_outputszRefactoringTool.print_outputcCs<x6|D].}tj |¡r&| |||¡q| |||¡qWdS)z)Refactor a list of files and directories.N)ÚosÚpathÚisdirÚ refactor_dirÚ refactor_file)rnÚitemsÚwriteÚ doctests_onlyZ dir_or_filerrrÚrefactors  zRefactoringTool.refactorc Cs¢tjd}x’t |¡D]„\}}}| d|¡| ¡| ¡xF|D]>}| d¡sBtj |¡d|krBtj ||¡} |  | ||¡qBWdd„|Dƒ|dd…<qWdS)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. ÚpyzDescending into %sr0rcSsg|]}| d¡s|‘qS)r0)r)r1Zdnrrrr4.sz0RefactoringTool.refactor_dir..N) r‘ÚextsepÚwalkr~r‚rr’Úsplitextrzr•) rnZdir_namer—r˜Zpy_extÚdirpathZdirnamesÚ filenamesrÚfullnamerrrr”s    zRefactoringTool.refactor_dirc CsŠyt|dƒ}Wn0tk r>}z| d||¡dSd}~XYnXzt |j¡d}Wd| ¡Xtj|d|dd}| ¡|fSQRXdS) zG Do our best to decode a Python source file correctly. ÚrbzCan't open %s: %s)NNNrr"rr)ÚencodingÚnewline) ÚopenÚOSErrorr‰rÚdetect_encodingrCÚcloserAÚread)rnrŽÚfÚerrr¢rrrÚ_read_python_source0s z#RefactoringTool._read_python_sourcecCsº| |¡\}}|dkrdS|d7}|rn| d|¡| ||¡}|jsL||kr`| |||||¡q¶| d|¡nH| ||¡}|jsŠ|rª|jrª|jt|ƒdd…|||dn | d|¡dS)zRefactors a file.NÚ zRefactoring doctests in %szNo doctest changes in %srp)r—r¢zNo changes in %s)r«r~Úrefactor_docstringrWÚprocessed_fileÚrefactor_stringÚ was_changedÚstr)rnrŽr—r˜Úinputr¢ÚoutputÚtreerrrr•@s    zRefactoringTool.refactor_filec Cs–t|ƒ}d|krtj|j_zLy|j |¡}Wn6tk rb}z| d||jj |¡dSd}~XYnXWd|j|j_X||_ |  d|¡|  ||¡|S)aFRefactor 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. rVzCan't parse %s: %s: %sNzRefactoring %s) rRr r_rr`Z parse_stringr!r‰Ú __class__rÚfuture_featuresr~Ú refactor_tree)rnÚdatarrOr´rªrrrr¯Ws     zRefactoringTool.refactor_stringcCsŒtj ¡}|rN| d¡| |d¡}|js2||krB| |d|¡qˆ| d¡n:| |d¡}|jsj|r~|jr~| t |ƒd|¡n | d¡dS)NzRefactoring doctests in stdinzzNo doctest changes in stdinzNo changes in stdin) ÚsysÚstdinr¨r~r­rWr®r¯r°r±)rnr˜r²r³r´rrrÚrefactor_stdinrs     zRefactoringTool.refactor_stdinc Csüx"t|j|jƒD]}| ||¡qW| |j| ¡¡| |j| ¡¡|j |  ¡¡}xtt |  ¡ƒrÎx^|jj D]P}||krv||rv||j tjjdd|jr¼||j tjjdxt||ƒD]ø}|||krê|| |¡y t|ƒWntk rwÌYnX|jr&||jkr&qÌ| |¡}|rÌ| ||¡}|dk rÌ| |¡x,| ¡D] }|jsng|_|j |¡q\W|j |  ¡¡}x2|D]*} | |kr¬g|| <||  || ¡q–WqÌWqvWq\Wx$t|j|jƒD]}| ||¡qàW|jS)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)rtÚreverse)rtN)rrgrhZ start_treeÚ traverse_byrlrmrkÚrunZleavesÚanyr*rZr‚rZBaseZdepthZkeep_line_orderZ get_linenor'ÚremoverÚ ValueErrorZfixers_appliedÚmatchÚ transformÚreplacerr,Z finish_treer°) rnr´rr.Z match_setÚnodeÚresultsÚnewZ new_matchesZfxrrrrr·‚sJ       $zRefactoringTool.refactor_treecCs^|sdSxP|D]H}xB||jD]4}| |¡}|r| ||¡}|dk r| |¡|}qWqWdS)aTraverse 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)rrÂrÃrÄ)rnrZZ traversalrÅr.rÆrÇrrrr½Ñs     zRefactoringTool.traverse_bycCs†|j |¡|dkr.| |¡d}|dkr.dS||k}| ||||¡|r`| d|¡|js`dS|rv| ||||¡n | d|¡dS)zR Called when a file has been refactored and there may be changes. NrzNo changes to %szNot writing changes to %s)rirr«rr~rWÚ write_file)rnrrŽrŒr—r¢rrrrr®ès  zRefactoringTool.processed_filec Cs®ytj|d|dd}Wn0tk rF}z| d||¡dSd}~XYnX|Fy| |¡Wn0tk rŒ}z| d||¡Wdd}~XYnXWdQRX| d|¡d|_dS) 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. Úwrr)r¢r£zCan't create %s: %sNzCan't write %s: %szWrote changes to %sT)rAr¤r¥r‰r—r~re)rnrrŽrŒr¢ÚfprªrrrrÈýs* zRefactoringTool.write_filez>>> z... c Csg}d}d}d}d}xØ|jddD]È}|d7}| ¡ |j¡r€|dk r\| | ||||¡¡|}|g}| |j¡} |d| …}q"|dk rº| ||j¡s®|||j ¡dkrº|  |¡q"|dk rØ| | ||||¡¡d}d}|  |¡q"W|dk 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.) NrT)Úkeependsrr¬rr) Ú splitlinesÚlstriprÚPS1r,Úrefactor_doctestÚfindÚPS2Úrstriprrz) rnr²rŽÚresultÚblockZ block_linenoÚindentÚlinenoÚlineÚirrrr­s:          z"RefactoringTool.refactor_docstringc s*yˆ ||ˆ¡}Wnftk rx}zHˆj tj¡rRx|D]}ˆ d| d¡¡q8Wˆ d|||j j |¡|Sd}~XYnXˆ  ||¡r&t |ƒj dd}|d|d…||dd…} }| dg|dksÔt| ƒ‚|d d¡sò|dd7<ˆˆj| d ¡g}|r&|‡‡fd 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Ërrprcsg|]}ˆˆj|‘qSr)rÑ)r1r×)rÕrnrrr4Zsz4RefactoringTool.refactor_doctest..)Ú parse_blockr!rYZ isEnabledForrcÚDEBUGr~rÒr‰rµrr·r±rÌÚAssertionErrorÚendswithrÎÚpop) rnrÔrÖrÕrŽr´rªr×rÇZclippedr)rÕrnrrÏ@s& "z RefactoringTool.refactor_doctestcCsÒ|jr d}nd}|js$| d|¡n&| d|¡x|jD]}| |¡q8W|jrt| d¡x|jD]}| |¡qbW|jrÎt|jƒdkr”| d¡n| dt|jƒ¡x&|jD]\}}}|j|f|ž|Žq®WdS) NÚwerez need to bezNo files %s modified.zFiles that %s modified:z$Warnings/messages while refactoring:rzThere was 1 error:zThere were %d errors:)rerir}rdrbrw)rnrÞÚfileÚmessager†r‡rˆrrrÚ summarize]s$     zRefactoringTool.summarizecCs"|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. )rZ parse_tokensÚ wrap_toksrDr¶)rnrÔrÖrÕr´rrrrÙtszRefactoringTool.parse_blockc csht | ||¡j¡}xN|D]F\}}\}}\} } } ||d7}| |d7} ||||f| | f| fVqWdS)z;Wraps a tokenize stream to systematically modify start/end.rN)rr@Ú gen_linesÚ__next__) rnrÔrÖrÕr+rrQZline0Zcol0Zline1Zcol1Z line_textrrrrâ~s   zRefactoringTool.wrap_toksccs€||j}||j}|}xV|D]N}| |¡r@|t|ƒd…Vn(|| ¡dkrXdVntd||fƒ‚|}qWx dVqrWdS)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¬zline=%r, prefix=%rrr)rÎrÑrrwrÒrÛ)rnrÔrÕÚprefix1Zprefix2Úprefixr×rrrrãŒs    zRefactoringTool.gen_lines)NN)FF)FF)FF)F)NFN)N)rrrr\ryrvrorfr‰r}r~rr™r”r«r•r¯r»r·r½r®rÈrÎrÑr­rÏrárÙrârãrrrrrU›s: 4(   O  + rUc@s eZdZdS)ÚMultiprocessingUnsupportedN)rrrrrrrrç srçcsBeZdZ‡fdd„Zd ‡fdd„ Z‡fdd„Z‡fd d „Z‡ZS) ÚMultiprocessRefactoringToolcs"tt|ƒj||Žd|_d|_dS)N)ÚsuperrèroÚqueueÚ output_lock)rnr‡Úkwargs)rµrrro¦sz$MultiprocessRefactoringTool.__init__Frc s|dkrttˆƒ |||¡Sy ddl‰Wntk r@t‚YnXˆjdk rTtdƒ‚ˆ ¡ˆ_ˆ  ¡ˆ_ ‡‡fdd„t |ƒDƒ}z.x|D] }|  ¡qˆWttˆƒ |||¡Wdˆj  ¡xt |ƒD]}ˆj d¡qÄWx|D]}| ¡rÞ|  ¡qÞWdˆ_XdS)Nrrz already doing multiple processescsg|]}ˆjˆjd‘qS))Útarget)ZProcessÚ_child)r1rØ)Úmultiprocessingrnrrr4¸sz8MultiprocessRefactoringTool.refactor..)rérèr™rïÚ ImportErrorrçrêÚ RuntimeErrorZ JoinableQueueZLockrëÚrangeÚstartrzÚputZis_alive)rnr–r—r˜Z num_processesZ processesr#rØ)rµ)rïrnrr™«s2               z$MultiprocessRefactoringTool.refactorcsR|j ¡}xB|dk rL|\}}ztt|ƒj||ŽWd|j ¡X|j ¡}q WdS)N)rêrarérèr•Z task_done)rnZtaskr‡rì)rµrrrîÈs     z"MultiprocessRefactoringTool._childcs2|jdk r|j ||f¡ntt|ƒj||ŽSdS)N)rêrôrérèr•)rnr‡rì)rµrrr•Ós  z)MultiprocessRefactoringTool.refactor_file)FFr)rrrror™rîr•Ú __classcell__rr)rµrrè¤s   rè)T)#rTÚ __author__rAr‘rr¹rcr€r%Ú itertoolsrZpgen2rrrZ fixer_utilrrrrr r rjrr!rrr/r5r7rRrSÚobjectrUrçrèrrrrÚ s8    (