gsk dZdZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z m Z mZddlmZddlmZmZdd lmZdd ZGd d eZd ZdZdZdZdZGddeZGddeZ GddeZ!Gdde Z"y)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 N)chain)drivertokenizetoken) find_root)pytreepygram) btm_matcherct|ggdg}g}tj|jD]0\}}}|j ds|r|dd}|j |2|S)zEReturn a sorted list of all available fix names in the given package.*fix_N) __import__pkgutil iter_modules__path__ startswithappend) fixer_pkg remove_prefixpkg fix_namesfindernameispkgs 7/opt/alt/python312/lib64/python3.12/lib2to3/refactor.pyget_all_fix_namesrsj YB .CI&33CLLAe ??6 "ABx   T " B c eZdZy) _EveryNodeN__name__ __module__ __qualname__rrr!r!+rr!ct|tjtjfr|jt |jhSt|tj r'|jrt|jSt t|tjr>t}|jD]#}|D]}|jt|%|Std|z)zf Accepts a pytree Pattern Node and returns a set of the pattern types which will match first. z$Oh no! I don't understand pattern %s) isinstancer NodePattern LeafPatterntyper!NegatedPatterncontent_get_head_typesWildcardPatternsetupdate Exception)patrpxs rr/r//s#**F,>,>?@ 88  z#v,,- ;;"3;;/ /#v--. EA+, :SA BBrcXtjt}g}|D]|}|jr2 t |j}|D]}||j |A|j||jj |l|j |~ttjjjtjjD]}||j|t|S#t $r|j |Y wxYw)z^ Accepts a list of fixers and returns a dictionary of head node type --> fixer list. ) collections defaultdictlistpatternr/rr! _accept_typerr python_grammar symbol2numbervaluestokensextenddict) fixer_list head_nodeseveryfixerheads node_types r_get_headnode_dictrJKs((.J E == 8' 6"'Iy)007"'!!-5--.55e< U#600>>EEG!00779 9$$U+9   $ U# $sD  D)(D)cLt|dDcgc] }|dz|z c}Scc}w)zN Return the fully qualified names for fixers in the package pkg_name. F.)r)pkg_namefix_names rget_fixers_from_packagerOds= .h> @> sNX %> @@ @s!c|SNr&)objs r _identityrSks Jrc|d}tjtj|jfd}t t jtjt jh}t} |\}}||vr|t jk(r|rnd}n|t jk(r|dk(r|\}}|t jk7s|dk7rn|\}}|t jk7s|dk7rn|\}}|t jk(r|dk(r |\}}|t jk(rT|j||\}}|t jk7s|dk7rn |\}}|t jk(rRnnt |S#t$r Yt |SwxYw) NFc.t}|d|dfS)Nrr)next)tokgens radvancez(_detect_future_features..advancers3i1vs1v~rTfrom __future__import(,)rgenerate_tokensioStringIOreadline frozensetrNEWLINENLCOMMENTr1STRINGNAMEOPadd StopIteration)sourcehave_docstringrYignorefeaturestpvaluerXs @r_detect_future_featuresrrosN  " "2;;v#6#?#? @C x{{EMMB CFuH  IBV|u||#!!%uzz!evo#I E#u '<#I E#u'8#I E>esl ' IBEJJ&LL' ' IBUXX~# ' IB EJJ&38 X    X  s>DF%F%% F;:F;ceZdZdZy) FixerErrorzA fixer could not be loaded.N)r#r$r%__doc__r&rrrtrts&rrtceZdZddddZdZdZddZdZdZd Z d Z d Z dd Z dd Z dZddZdZd dZdZdZ d!dZd"dZdZdZdZdZdZdZdZdZy)#RefactoringToolF)print_function exec_functionwrite_unchanged_filesFixrNc||_|xsg|_|jj|_||jj |t jj|_|jdr|jjd=n&|jdr|jjd=|jjd|_ g|_ tjd|_g|_d|_t%j&|jt(j*|j |_|j-\|_|_g|_t5j6|_g|_g|_t?|j0|j.D]~}|j@r|j8jC|+||j.vr|j:jE|U||j0vsd|j<jE|tG|j:|_$tG|j<|_%y) 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. NrxprintryexecrzrwF)convertlogger)&fixersexplicit_default_optionscopyoptionsr2r r>grammarkeywordsgetrzerrorslogging getLoggerr fixer_logwroterDriverr r get_fixers pre_order post_orderfilesbm BottomMatcherBM bmi_pre_orderbmi_post_orderr BM_compatible add_fixerrrJbmi_pre_order_headsbmi_post_order_heads)self fixer_namesrrrGs r__init__zRefactoringTool.__init__s"  B ,,113   LL   (,,113 <<( ) %%g. \\/ * %%f- &*\\%5%56M%N" ''(9:  mmDLL,2NN+/;;8 +///*;' ""$ 4??DNN;E""!!%($..(""))%0$//)##**51<$6d6H6H#I $6t7J7J$K!rc g}g}|jD]w}t|iidg}|jddd}|j|jr|t |jd}|j d}|jdj|Dcgc]}|jc}z} t||} | |j|j} | jr0|jd ur"||jvr|j!d | |j#d || j$d k(r|j'| @| j$d k(r|j'| btd| j$zt)j*d} |j-| |j-| ||fScc}w#t$rtd|d|dwxYw)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 rLrN_z Can't find TzSkipping optional fixer: %szAdding transformation: %sprepostzIllegal fixer order: %r run_orderkey)rrrsplitr FILE_PREFIXlensplit CLASS_PREFIXjointitlegetattrAttributeErrorrtrrr log_message log_debugorderroperator attrgettersort) rpre_order_fixerspost_order_fixers fix_mod_pathmodrNpartsr6 class_name fix_classrGkey_funcs rrzRefactoringTool.get_fixerss KKL\2rC59C#**3226H""4#3#34#C(8(8$9$:;NN3'E**RWW5OAaggi5O-PPJ X#C4 dllDNN;E~~$--t";  5  !>I NN6 A{{e# ''.&!((/ !:U[[!HII/(2&&{3(+8, "344-6P" X x!LMSWW XsG 8 GG*c)zCalled when an error occurs.r&)rmsgargskwdss r log_errorzRefactoringTool.log_errors rcH|r||z}|jj|y)zHook to log a message.N)rinforrrs rrzRefactoringTool.log_messages *C rcH|r||z}|jj|yrQ)rdebugrs rrzRefactoringTool.log_debug s *C #rcy)zTCalled with the old version, new version, and filename of a refactored file.Nr&)rold_textnew_textfilenameequals r print_outputzRefactoringTool.print_outputs rc|D]H}tjj|r|j|||6|j |||Jy)z)Refactor a list of files and directories.N)ospathisdir refactor_dir refactor_file)ritemswrite doctests_only dir_or_files rrefactorzRefactoringTool.refactorsB!Kww}}[)!!+umD"";}E !rctjdz}tj|D]\}}}|jd||j |j |D]m}|j drtj j|d|k(s;tj j||} |j| ||o|D cgc]} | j dr| c} |ddycc} w)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. pyzDescending into %srLrN) rextsepwalkrrrrsplitextrr) rdir_namerrpy_extdirpathdirnames filenamesrfullnamedns rrzRefactoringTool.refactor_dir sT!,.GGH,= (GXy NN/ 9 MMO NN !,GG$$T*1-7!ww||GT:H&&x F " )1K" c8J2KHQK->Ls C</C<c t|d} tj|j d}|j tj|d|d5}|j|fcdddS#t$r}|jd||Yd}~yd}~wwxYw#|j wxYw#1swYyxYw) zG Do our best to decode a Python source file correctly. rbzCan't open %s: %sNNNrr5rencodingnewline) openOSErrorrrdetect_encodingrbcloser`read)rrferrrs r_read_python_sourcez#RefactoringTool._read_python_source4s Xt$A // ;A>H GGI WWXsXr Ba668X%C B  NN.# >  GGI B Bs. A6"BB46 B?BBB14B=c|j|\}}|y|dz }|r^|jd||j||}|js||k7r|j |||||y|jd|y|j ||}|js|r.|j r"|j t|dd|||y|jd|y)zRefactors a file.N zRefactoring doctests in %szNo doctest changes in %sr)rrzNo changes in %s)rrrefactor_docstringrzprocessed_filerefactor_string was_changedstr)rrrrinputroutputtrees rrzRefactoringTool.refactor_fileDs228<x =     NN7 B,,UH=F))Vu_##FHeUHM98D''x8D))dt7G7G##CIcrNH*/($D18 "&,,DKK    #',,DKK s)B C*(C%C-%C**C--D ctjj}|rZ|jd|j |d}|j s||k7r|j |d|y|jdy|j|d}|j s|r)|jr|j t|d|y|jdy)NzRefactoring doctests in stdinzzNo doctest changes in stdinzNo changes in stdin) sysstdinrrrrzrrrr)rrrrrs rrefactor_stdinzRefactoringTool.refactor_stdinvs    NN: ;,,UI>F))Vu_##FIu=<=''y9D))dt7G7G##CIy%@45rct|j|jD]}|j|||j |j |j|j |j |j|jj|j}t|jr|jjD]}||vs ||s||jtjj d|j"r-||jtjj$t'||D]}|||vr||j)| t+||j.r||j.vrF|j1|}|sZ|j3||}|o|j5||jD]0}|j.sg|_|j.j7|2|jj|j}|D]"} | |vrg|| <|| j9|| $t|jrt|j|jD]}|j;|||j<S#t,$rYwxYw)aRefactors 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)rreverser)rrr start_tree traverse_byrrrrunleavesanyr@rrr Basedepthkeep_line_order get_linenor;remover ValueErrorfixers_appliedmatch transformreplacerrB finish_treer) rrrrG match_setnoderesultsnew new_matchesfxrs rrzRefactoringTool.refactor_treesv 4>>4??;E   T4 (< 114>>3CD 22DOO4EFGGKK . )""$%I%)E*:e$))fkk.?.?)N,,"%(--&++2H2H-I $Yu%5 69U#33%e,33D9%%dO  ..5D+>>@(;$($7$7$>$>u$E -=/3ggkk#**,.G +6C+.)+;79 #$-cN$9$9+c:J$K ,7A!7()""$%b4>>4??;E   dD )<E *%%%s K  K-,K-c|sy|D]R}||jD]>}|j|}|s|j||}|,|j||}@Ty)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,rrr)rr traversalrrGrrs rr zRefactoringTool.traverse_bys^ D *++d+//$8C S)" +rc2|jj|||j|d}|y||k(}|j|||||r|j d||j sy|r|j ||||y|j d|y)zR Called when a file has been refactored and there may be changes. NrzNo changes to %szNot writing changes to %s)rrrrrrz write_file)rrrrrrrs rrzRefactoringTool.processed_files (#  //9!  NN-x 8--  OOHh( C NN6 Arc` tj|d|d}|5 |j |ddd|j d|d|_y#t$r}|jd||Yd}~yd}~wwxYw#t$r}|jd||Yd}~ld}~wwxYw#1swYuxYw) 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. wrrzCan't create %s: %sNzCan't write %s: %szWrote changes to %sT)r`rrrrrr)rrrrrfprs rr$zRefactoringTool.write_files 32FB  D" ,h7   NN0(C @   D3XsCC DRsEAB$A; A8A33A8; B!BB$B!!B$$B-z>>> z... c g}d}d}d}d}|jdD] }|dz }|jj|jrK|#|j |j |||||}|g}|j |j} |d| }}|S|j||jzs#|||jjzdzk(r|j||#|j |j ||||d}d}|j||#|j |j ||||dj|S)aRefactors 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.) NrTkeependsrrr) splitlineslstriprPS1rBrefactor_doctestfindPS2rstriprr) rrrresultblock block_linenoindentlinenolineis rrz"RefactoringTool.refactor_docstringsg $$d$3D aKF{{}''1$MM$"7"7|8>#JK% IIdhh'bq$??6DHH#456DHHOO$55<< T"$MM$"7"7|8>#JK d#)4*   MM$//|06B Cwwvrc |j|||}|j||rt|jd}|d|dz ||dz d}} |djds |dxxdz cc<||jz|j!d zg}|r#||Dcgc]}||j"z|zc}z }|S#t$r}|jjtj r(|D]#}|j d|jd%|jd|||jj||cYd}~Sd}~wwxYwcc}w) 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: %srz+Can't parse docstring in %s line %s: %s: %sNTr)rrr) parse_blockr3r isEnabledForrDEBUGrr1rrr#rrr+endswithr-popr0) rr3r6r5rrrr7rclippeds rr.z RefactoringTool.refactor_doctestDsC ##E66:D   dH -d)&&&5Cyq>3vaxy>SGr7##D)B4dhh&34EsCst&488+d2sCC # {{'' 6!DNN<T1BC" NNH#VS]]-C-CS JL   Ds$B<E< E A;EE E cX|jrd}nd}|js|jd|n4|jd||jD]}|j||jr3|jd|jD]}|j||jr{t |jdk(r|jdn%|jdt |j|jD]\}}}|j|g|i|yy) Nwerez need to bezNo files %s modified.zFiles that %s modified:z$Warnings/messages while refactoring:rzThere was 1 error:zThere were %d errors:)rrrrrr)rrAfilemessagerrrs r summarizezRefactoringTool.summarizeas ::DDzz   4d ;   6 =   &# >>   C D>>  )* ;;4;;1$  !56  !8#dkk:JK#';;T4   4t4t4$/ rc||jj|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 parse_tokens wrap_toksrcr)rr3r6r5rs rr:zRefactoringTool.parse_blockxs4 {{''uff(MN({ rc#Ktj|j||j}|D]+\}}\}}\} } } ||dz z }| |dz z } ||||f| | f| f-yw)z;Wraps a tokenize stream to systematically modify start/end.rN)rr_ gen_lines__next__) rr3r6r5rAr,rqline0col0line1col1 line_texts rrGzRefactoringTool.wrap_tokss}))$..*G*P*PQDJ @D%% y VaZ E VaZ E t}udmYF FEKsA!A#c#K||jz}||jz}|}|D]R}|j|r|t|dn,||j dzk(rdnt d|d||}T dw)zGenerates lines as expected by tokenize from a list of lines. This strips the first len(indent + self.PS1) characters off each line. Nrzline=z , prefix=r)r-r0rrr1AssertionError)rr3r5prefix1prefix2prefixr7s rrIzRefactoringTool.gen_liness 488#488#Dv&3v;<((4// $T6%JKKFHsA>Br)FF)F)NFNrQ)r#r$r%rrrrrrrrrrrrrrrrr rr$r-r0rr.rDr:rGrIr&rrrwrws+0).279LK3Ln&5P   FL(& =.66 M ^#.GL $B** C C)V:5. Grrwc eZdZy)MultiprocessingUnsupportedNr"r&rrrVrVr'rrVcBeZdZfdZ dfd ZfdZfdZxZS)MultiprocessRefactoringToolcHtt| |i|d|_d|_yrQ)superrXrqueue output_lockrrkwargsrs rrz$MultiprocessRefactoringTool.__init__s' )494J6J rc|dk(rtt| |||S ddl}|j td|j|_|j|_ t|Dcgc]}|j|j }} |D]}|jtt| ||||j jt|D]}|j j!d|D]#}|j#s|j%d|_y#t$rt wxYwcc}w#|j jt|D]}|j j!d|D]#}|j#s|j%d|_wxYw)Nrrz already doing multiple processes)target)rZrXrmultiprocessing ImportErrorrVr[ RuntimeError JoinableQueueLockr\rangeProcess_childstartrputis_alive) rrrr num_processesrar8 processesr6rs rrz$MultiprocessRefactoringTool.refactors A 4dDum- - - " :: !AB B$224 *//1#M242%,,DKK,@2 4   -t =eU>K M JJOO =) t$*::<FFHDJ) -, , - 4 JJOO =) t$*::<FFHDJs$D6/#E ,E6EAG*Gc|jj}|Q|\}} tt||i||jj |jj}|Pyy#|jj wxYwrQ)r[rrZrXr task_done)rtaskrr^rs rrhz"MultiprocessRefactoringTool._childszz~~LD& '14F%#% $$&::>>#D  $$&s A00B c~|j|jj||fytt||i|SrQ)r[rjrZrXrr]s rrz)MultiprocessRefactoringTool.refactor_filesA :: ! JJNND&> *4dI!! !r)FFr)r#r$r%rrrhr __classcell__)rs@rrXrXs$ :? : $!!rrX)T)#ru __author__r`rrrrrr9 itertoolsrpgen2rrr fixer_utilrrr r r rrr3r!r/rJrOrSrrrtobjectrwrVrXr&rrrxs3   +*!   C82@%P''FfFR  4!/4!r