o ?Ogskã@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_matcherTcCsTt|ggdgƒ}g}t |j¡D]\}}}| d¡r'|r"|dd…}| |¡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_prefixZpkgZ fix_namesÚfinderÚnameZispkg©rú7/opt/alt/python310/lib64/python3.10/lib2to3/refactor.pyÚget_all_fix_namess   €rc@ó eZdZdS)Ú _EveryNodeN©Ú__name__Ú __module__Ú __qualname__rrrrr+órcCsŽt|tjtjfƒr|jdurt‚|jhSt|tjƒr$|jr"t|jƒSt‚t|tj ƒrAt ƒ}|jD]}|D] }|  t|ƒ¡q4q0|St 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) Ú isinstancerZ NodePatternZ LeafPatternÚtyperZNegatedPatternZcontentÚ_get_head_typesZWildcardPatternÚsetÚupdateÚ Exception)ZpatÚrÚpÚxrrrr!/s      ÿ r!c Cs¼t t¡}g}|D];}|jr1zt|jƒ}Wnty#| |¡Yq w|D] }|| |¡q&q |jdur?||j |¡q | |¡q tt 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!rrZ _accept_typerr Úpython_grammarZ symbol2numberÚvaluesÚtokensÚextendÚdict)Z fixer_listZ head_nodesZeveryÚfixerZheadsZ node_typerrrÚ_get_headnode_dictKs(  ÿÿ   ÿr2cs‡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©Zpkg_namerrÚ hsÿz+get_fixers_from_package..F)rr7rr7rÚget_fixers_from_packageds ÿr9cCs|S©Nr)ÚobjrrrÚ _identityksr<csjd}t t |¡j¡‰‡fdd„}ttjtjtj hƒ}t ƒ}zŠ |ƒ\}}||vr*q|tj kr5|r2ncd}n_|tj kr“|dkr“|ƒ\}}|tj ksL|dkrMnR|ƒ\}}|tj ks[|dkr\nH|ƒ\}}|tj kro|dkro|ƒ\}}|tj kr’| |¡|ƒ\}}|tj ks‡|d krˆn |ƒ\}}|tj kstnnq Wt|ƒSWt|ƒSWt|ƒSWt|ƒSty´Yt|ƒSw) 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_docstringrAÚignoreÚfeaturesÚtpÚvaluerr?rÚ_detect_future_featuresos\            û€çýïò þþrXc@seZdZdZdS)Ú FixerErrorzA fixer could not be loaded.N)rrrÚ__doc__rrrrrY—srYc@sêeZdZddddœZdZdZd4dd„Zdd „Zd d „Zd d „Z dd„Z dd„Z d5dd„Z d5dd„Z dd„Zd5dd„Zdd„Zd6dd„Zdd„Zd d!„Z  d7d"d#„Zd8d$d%„Zd&Zd'Zd(d)„Zd*d+„Zd,d-„Zd.d/„Zd0d1„Zd2d3„ZdS)9ÚRefactoringToolF)Úprint_functionÚ exec_functionÚwrite_unchanged_filesZFixr NcCsH||_|pg|_|j ¡|_|dur|j |¡tj ¡|_|jdr)|jj d=n |jdr3|jj d=|j  d¡|_ g|_ t  d¡|_g|_d|_tj|jtj|jd |_| ¡\|_|_g|_t ¡|_g|_g|_t|j|jƒD]#}|j r~|j !|¡qr||jvrŠ|j "|¡qr||jvr•|j "|¡qrt#|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. Nr\Úprintr]Úexecr^r[F)ÚconvertÚlogger)&ÚfixersÚexplicitÚ_default_optionsÚcopyÚoptionsr#r r,ÚgrammarÚkeywordsÚgetr^ÚerrorsÚloggingZ getLoggerrbÚ fixer_logÚwroterZDriverrraÚ get_fixersÚ pre_orderÚ post_orderÚfilesÚbmZ BottomMatcherÚBMZ bmi_pre_orderZbmi_post_orderrZ BM_compatibleZ add_fixerrr2Úbmi_pre_order_headsÚbmi_post_order_heads)ÚselfZ fixer_namesrgrdr1rrrÚ__init__¤sD         þ    € zRefactoringTool.__init__c CsJg}g}|jD]ˆ}t|iidgƒ}| dd¡d}| |j¡r(|t|jƒd…}| d¡}|jd dd „|Dƒ¡}zt ||ƒ}Wnt yQt d ||fƒd‚w||j |j ƒ} | jrm|jd urm||jvrm| d |¡q| d |¡| jdkr~| | ¡q| jdkr‰| | ¡qt d| jƒ‚t 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 r4réÿÿÿÿNÚ_ÚcSsg|]}| ¡‘qSr)Útitle)r5r&rrrr8ësz.RefactoringTool.get_fixers..zCan't find %s.%sTzSkipping optional fixer: %szAdding transformation: %sZpreZpostzIllegal fixer order: %rZ run_order©Úkey)rcrÚrsplitrÚ FILE_PREFIXÚlenÚsplitÚ CLASS_PREFIXÚjoinÚgetattrÚAttributeErrorrYrgrmrdÚ log_messageÚ log_debugZorderrÚoperatorÚ attrgetterÚsort) rwZpre_order_fixersZpost_order_fixersZ fix_mod_pathÚmodr6ÚpartsÚ class_nameZ fix_classr1Zkey_funcrrrroÛs:    ÿ          zRefactoringTool.get_fixerscOs‚)zCalled when an error occurs.r)rwÚmsgÚargsÚkwdsrrrÚ log_errorszRefactoringTool.log_errorcGs|r||}|j |¡dS)zHook to log a message.N)rbÚinfo©rwrrrrrr‡szRefactoringTool.log_messagecGs|r||}|j |¡dSr:)rbÚdebugr”rrrrˆ szRefactoringTool.log_debugcCsdS)zTCalled with the old version, new version, and filename of a refactored file.Nr)rwÚold_textÚnew_textÚfilenameÚequalrrrÚ print_outputszRefactoringTool.print_outputcCs8|D]}tj |¡r| |||¡q| |||¡qdS)z)Refactor a list of files and directories.N)ÚosÚpathÚisdirÚ refactor_dirÚ refactor_file)rwÚitemsÚwriteÚ doctests_onlyZ dir_or_filerrrÚrefactors  üzRefactoringTool.refactorc Csštjd}t |¡D]@\}}}| d|¡| ¡| ¡|D]}| d¡s>tj |¡d|kr>tj ||¡} |  | ||¡qdd„|Dƒ|dd…<q dS)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 %sr4rcSsg|] }| d¡s|‘qSr3)r)r5Zdnrrrr82óz0RefactoringTool.refactor_dir..N) r›ÚextsepÚwalkrˆr‹rrœÚsplitextr„rŸ) rwZdir_namer¡r¢Zpy_extÚdirpathZdirnamesÚ filenamesrÚfullnamerrrrž s   €özRefactoringTool.refactor_dirc Cs®zt|dƒ}Wnty!}z| d||¡WYd}~dSd}~wwzt |j¡d}W| ¡n| ¡wtj|d|dd}| ¡|fWdƒS1sPwYdS) zG Do our best to decode a Python source file correctly. ÚrbzCan't open %s: %sN©NNrr%r{©ÚencodingÚnewline) ÚopenÚOSErrorr’rÚdetect_encodingrIÚcloserGÚread)rwr˜ÚfÚerrr¯rrrÚ_read_python_source4s€þ $ÿz#RefactoringTool._read_python_sourcecCsÀ| |¡\}}|dur dS|d7}|r9| d|¡| ||¡}|js&||kr1| |||||¡dS| d|¡dS| ||¡}|jsG|rX|jrX|jt|ƒdd…|||ddS| d|¡dS)zRefactors a file.NÚ zRefactoring doctests in %szNo doctest changes in %sry)r¡r¯zNo changes in %s)r¸rˆÚrefactor_docstringr^Úprocessed_fileÚrefactor_stringÚ was_changedÚstr)rwr˜r¡r¢Úinputr¯ÚoutputÚtreerrrrŸDs     ÿzRefactoringTool.refactor_filec Cs°t|ƒ}d|vr tj|j_z3z|j |¡}Wn#ty9}z| d||jj |¡WYd}~W|j|j_dSd}~wwW|j|j_n|j|j_w||_ |  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. r\zCan't parse %s: %s: %sNzRefactoring %s) rXr Z!python_grammar_no_print_statementrrhZ parse_stringr$r’Ú __class__rÚfuture_featuresrˆÚ refactor_tree)rwÚdatarrUrÁr·rrrr¼[s&   ÿ €ûÿ  zRefactoringTool.refactor_stringcCs’tj ¡}|r)| d¡| |d¡}|js||kr"| |d|¡dS| d¡dS| |d¡}|js7|rB|jrB| t |ƒd|¡dS| d¡dS)NzRefactoring doctests in stdinzzNo doctest changes in stdinzNo changes in stdin) ÚsysÚstdinrµrˆrºr^r»r¼r½r¾)rwr¢r¿rÀrÁrrrÚrefactor_stdinvs    zRefactoringTool.refactor_stdinc CsÌt|j|jƒD]}| ||¡q| |j| ¡¡| |j| ¡¡|j |  ¡¡}t |  ¡ƒrÓ|jj D]˜}||vrÌ||rÌ||j tjjdd|jrV||j tjjdt||ƒD]o}|||vrk|| |¡zt|ƒWn tyzYq\w|jr„||jvr„q\| |¡}|rË| ||¡}|durË| |¡| ¡D]}|js¦g|_|j |¡qž|j |  ¡¡}|D]} | |vrÁg|| <||  || ¡q·q\q4t |  ¡ƒs0t|j|jƒD]}| ||¡qÚ|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)r~Úreverser}N)rrprqZ start_treeÚ traverse_byrurvrtÚrunZleavesÚanyr-rcr‹rZBaseZdepthZkeep_line_orderZ get_linenor*ÚremoverÚ ValueErrorZfixers_appliedÚmatchÚ transformÚreplacerr/Z finish_treer½) rwrÁrr1Z match_setÚnodeÚresultsÚnewZ new_matchesZfxrrrrrĆsP     ý    € Ñ1zRefactoringTool.refactor_treecCsV|sdS|D]"}||jD]}| |¡}|r'| ||¡}|dur'| |¡|}q qdS)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)r rÏrÐrÑ)rwrcZ traversalrÒr1rÓrÔrrrrÊÕs    €úÿzRefactoringTool.traverse_bycCsˆ|j |¡|dur| |¡d}|durdS||k}| ||||¡|r0| d|¡|js0dS|r<| ||||¡dS| d|¡dS)zR Called when a file has been refactored and there may be changes. NrzNo changes to %szNot writing changes to %s)rrrr¸ršrˆr^Ú write_file)rwr—r˜r–r¡r¯r™rrrr»ìs  zRefactoringTool.processed_filec CsÈz tj|d|dd}Wnty%}z| d||¡WYd}~dSd}~ww|)z| |¡WntyI}z | d||¡WYd}~nd}~wwWdƒn1sTwY| 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. Úwr{r®zCan't create %s: %sNzCan't write %s: %szWrote changes to %sT)rGr±r²r’r¡rˆrn)rwr—r˜r–r¯Úfpr·rrrrÕs$€þ€ÿ€ý  zRefactoringTool.write_filez>>> z... c Csg}d}d}d}d}|jddD]d}|d7}| ¡ |j¡r?|dur-| | ||||¡¡|}|g}| |j¡} |d| …}q|dur\| ||j¡sV|||j ¡dkr\|  |¡q|durk| | ||||¡¡d}d}|  |¡q|dur„| | ||||¡¡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¹r{) Ú splitlinesÚlstriprÚPS1r/Úrefactor_doctestÚfindÚPS2Úrstriprr„) rwr¿r˜ÚresultÚblockZ block_linenoÚindentÚlinenoÚlineÚirrrrºsB  ÿ ÿ  ÿ  ÿ z"RefactoringTool.refactor_docstringc sz ˆ ||ˆ¡}Wn4ty=}z(ˆj tj¡r&|D] }ˆ d| d¡¡qˆ d|||j j |¡|WYd}~Sd}~wwˆ  ||¡r…t |ƒj dd}|d|d…||dd…} }|d d¡sl|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: %sNTrØrryrcsg|] }ˆˆj|‘qSr)rß)r5rå©rãrwrrr8^r¥z4RefactoringTool.refactor_doctest..)Ú parse_blockr$rbZ isEnabledForrlÚDEBUGrˆràr’rÂrrÄr¾rÚÚendswithrÜÚpop) rwrârärãr˜rÁr·rårÔZclippedrrçrrÝDs* ÿ€ú "z RefactoringTool.refactor_doctestcCsÐ|jrd}nd}|js| d|¡n| d|¡|jD]}| |¡q|jr6| d¡|jD]}| |¡q.|jrdt|jƒdkrF| d¡n | dt|jƒ¡|jD]\}}}|j|g|¢Ri|¤ŽqRdSdS) 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:)rnrrr‡rmrkr)rwrìÚfileÚmessagerrr‘rrrÚ summarizeas(       ú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_toksrJrÃ)rwrârärãrÁrrrrèxszRefactoringTool.parse_blockc csft | ||¡j¡}|D]#\}}\}}\} } } ||d7}| |d7} ||||f| | f| fVq dS)z;Wraps a tokenize stream to systematically modify start/end.rN)rrFÚ gen_linesÚ__next__) rwrârärãr.r rWZline0Zcol0Zline1Zcol1Z line_textrrrrð‚s€  øzRefactoringTool.wrap_toksccsx||j}||j}|}|D]'}| |¡r |t|ƒd…Vn|| ¡dkr,dVntd||fƒ‚|}q dVq8)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=%rTr{)rÜrßrrràÚAssertionError)rwrârãÚprefix1Zprefix2Úprefixrårrrrñs€   ÿzRefactoringTool.gen_linesr­)FF)F)NFNr:)rrrrerƒr€rxror’r‡rˆršr£ržr¸rŸr¼rÈrÄrÊr»rÕrÜrßrºrÝrïrèrðrñrrrrr[›sBþ 7(    O ÿ + r[c@r)ÚMultiprocessingUnsupportedNrrrrrrö¤rröcsFeZdZ‡fdd„Z  d ‡fdd„ Z‡fdd„Z‡fd d „Z‡ZS) ÚMultiprocessRefactoringToolcs&tt|ƒj|i|¤Žd|_d|_dSr:)Úsuperr÷rxÚqueueÚ output_lock©rwrÚkwargs©rÂrrrxªs z$MultiprocessRefactoringTool.__init__Frc s2|dkrttˆƒ |||¡Szddl‰Wn tyt‚wˆjdur'tdƒ‚ˆ ¡ˆ_ˆ  ¡ˆ_ ‡‡fdd„t |ƒDƒ}z8|D]}|  ¡q@ttˆƒ |||¡Wˆj  ¡t |ƒD]}ˆj d¡q[|D] }| ¡rp|  ¡qfdˆ_dSˆj  ¡t |ƒD]}ˆj d¡q|D] }| ¡r”|  ¡qŠdˆ_w)Nrrz already doing multiple processescsg|] }ˆjˆjd‘qS))Útarget)ZProcessÚ_child)r5ræ©Úmultiprocessingrwrrr8¼sÿz8MultiprocessRefactoringTool.refactor..)rør÷r£rÚ ImportErrorrörùÚ RuntimeErrorZ JoinableQueueZLockrúÚrangeÚstartr„ÚputZis_alive)rwr r¡r¢Z num_processesZ processesr&rærýrrr£¯sL ÿ  ÿ    ÿ ÿ  €  ú €z$MultiprocessRefactoringTool.refactorcsf|j ¡}|dur1|\}}ztt|ƒj|i|¤ŽW|j ¡n|j ¡w|j ¡}|dus dSdSr:)rùrjrør÷rŸZ task_done)rwZtaskrrürýrrrÿÌs  ÿÿ ùz"MultiprocessRefactoringTool._childcs4|jdur|j ||f¡dStt|ƒj|i|¤ŽSr:)rùrrør÷rŸrûrýrrrŸ×s  ÿÿz)MultiprocessRefactoringTool.refactor_file)FFr)rrrrxr£rÿrŸÚ __classcell__rrrýrr÷¨s ÿ  r÷)T)#rZÚ __author__rGr›rrÆrlr‰r(Ú itertoolsrZpgen2rrrZ fixer_utilrr{rr r rsrr$rr!r2r9r<rXrYÚobjectr[rör÷rrrrÚs:     (