ZL is dZddlZddlmZmZddlmZddlmZm Z m Z m Z m Z ddl mZddlmZmZmZmZmZmZmZddlmZdd lmZdd lmZmZdd lmZm Z dd l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+dd l,m-Z-m.Z.m/Z/ddl0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6ddl7m8Z8ddl9m:Z:m;Z;Gdde<Z=edZ>ee:e;fZ?eee ee ge efZ@eAZBeAZCeAZDeAZEe/e>e=fZFeFeGeBZHeIgdZJdeKde-e=fdZLdede ede de efdZMdedeAdeNeAdeOfdZPdedeAdeNeAdeOfdZQd eGe:deOfd!ZRGd"d#eZSeGd$d%ZTeUeEeKfZVeGd&d'ZWGd(d)eSeWZXGd*d+eSZYGd,d-eSZZd.eKde eUeAeAffd/Z[d.eKdeOfd0Z\d1eKd2eKdeKfd3Z]Gd4d5eZeWZ^Gd6d7eZeWZ_Gd8d9Z`d:e:dee?gdffd;Zadz7 String transformers that can split and merge strings. N)ABCabstractmethod) defaultdict)Callable CollectionIterableIteratorSequence) dataclass)AnyClassVarFinalLiteralOptionalTypeVarUnion)trait)contains_pragma_comment)Line append_leaves)FeatureMode) CLOSING_BRACKETSOPENING_BRACKETSSTANDALONE_COMMENT is_empty_lpar is_empty_par is_empty_rparis_part_of_annotation parent_type replace_childsyms)ErrOkResult)assert_is_leaf_stringcount_chars_in_widthget_string_prefixhas_triple_quotesnormalize_string_quotes str_width)token)LeafNodeceZdZdZy)CannotTransformz-Base class for errors raised by Transformers.N)__name__ __module__ __qualname____doc__Q/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/black/trans.pyr0r0*s7r6r0T)u、u。u,err_msgreturnc.t|}t|S)zW(T)ransform Err Convenience function used when working with the TResult type. )r0r#)r9cant_transforms r7TErrr=<s %W-N ~ r6linefeaturesmodec#" KjD]!}|jtjk(s!n t ddt dt ddtffd dt dt ddtf fd }j}d}tjD]\}}|j}|r d |_ d}d |cxkxrtjd z kncxr\|jtjk(xr=||d z d xr.j|d z jdk7xr ||d zd }|rd |_ |j|dj|D]} |j| d|yw)z>A transformer which normalizes spacing around power operators.z*No doublestar token was found in the line.indexkindr:c|dk(r+t|tjtjhSt |tj tj hS)NrF)handle_is_simple_look_up_prevr,RPARRSQBhandle_is_simple_lookup_forwardLPARLSQB)rBrCr>s r7is_simple_lookupz&hug_power_op..is_simple_lookupQsI 2:0uuzz5::>VW W2eejj%**5 r6cj|}|jtjtjhvr ||S|jtj tj tjhvrIj|dzjtjtjhvr |dzdSy)NrErCF)leavestyper,NAMENUMBERPLUSMINUSTILDE)rBrCstartrNr>s r7is_simple_operandz'hug_power_op..is_simple_operand\s E" ::%**ell3 3#E40 0 ::%**ekk5;;? ?{{519%**uzz5<<.HH( ::r6FrrErFrPlambdaT preformattedN)rQrRr, DOUBLESTARr0intrboolclone enumerateprefixlenvalueappendcomments_after) r>r?r@leafrYnew_line should_hugidxnew_leaf comment_leafrNs ` @r7 hug_power_oprnEs  L 99(( ( LJKK  75> d GENt zz|HJt{{+= T::<  HOJ +s4;;'!+ + 3 U--- 3!#'3 3 C!G$**h6 3"#'2   HO t4 //5 =L OOLtO < =)=. Ns -FEFrB disallowedcd}g}d|cxkrt|jkriny|j|}|j||s|j|vrd}t |s| S|dz}d|cxkrt|jkrdyy)z Handling the determination of is_simple_lookup for the lines prior to the doublestar token. This is required because of the need to isolate the chained expression to determine the bracket or parenthesis belong to the single expression. FrTrE)rdrQrfrRis_expression_chained)r>rBrocontains_disallowedchaincurrents r7rHrHs   E u 's4;;' ' ++e$ W"w||z'A"& $U+** *   u 's4;;' '  ( r6cd|cxkrt|jkrny|j|}|j|vry|jtjtj hvs,|jtjk(r|j dk(ry|dz }d|cxkrt|jkryy)a Handling decision is_simple_lookup for the lines behind the doublestar token. This function is simplified to keep consistent with the prior logic and the forward case are more straightforward and do not need to care about chained expressions. rFforTrE)rdrQrRr,rSDOTre)r>rBrorts r7rKrKs u 's4;;' ' ++e$ <<: % << EII6 6 LLEJJ &7==E+A    u 's4;;' '  ( r6chained_leavesc(t|dkry|d}|d}|jtjk(r|jtjhvS|jtj tj hvr,|jtj tj hvS|jtjtjhvr;|jtjtjtjhvSy)z Function to determine if the variable is a chained call. (e.g., foo.lookup, foo().lookup, (foo.lookup())) will be recognized as chained call) TrFF) rdrRr,rSrwrIrJrLrM)rx current_leaf past_leafs r7rqrqs  >Q!"%Lr"I~~#  UYYK// EJJ 3 3  UZZ$<<< EJJ 3 3  UZZUZZ$HHHr6c eZdZUdZdZeed<dededdfdZe de de fd Z e de d e edeee fd Zde d eed edee fdZy)StringTransformera An implementation of the Transformer protocol that relies on its subclasses overriding the template methods `do_match(...)` and `do_transform(...)`. This Transformer works exclusively on strings (for example, by merging or splitting them). The following sections can be found among the docstrings of each concrete StringTransformer subclass. Requirements: Which requirements must be met of the given Line for this StringTransformer to be applied? Transformations: If the given Line meets all of the above requirements, which string transformations can you expect to be applied to it by this StringTransformer? Collaborations: What contractual agreements does this StringTransformer have with other StringTransfomers? Such collaborations should be eliminated/minimized as much as possible. r1 line_lengthnormalize_stringsr:Nc ||_||_yN)rr)selfrrs r7__init__zStringTransformer.__init__s&!2r6r>cy)a Returns: * Ok(string_indices) such that for each index, `line.leaves[index]` is our target string if a match was able to be made. For transformers that don't result in more lines (e.g. StringMerger, StringParenStripper), multiple matches and transforms are done at once to reduce the complexity. OR * Err(CannotTransform), if no match could be made. Nr5rr>s r7do_matchzStringTransformer.do_matchr6string_indicescy)a, Yields: * Ok(new_line) where new_line is the new transformed line. OR * Err(CannotTransform) if the transformation failed for some reason. The `do_match(...)` template method should usually be used to reject the form of the given Line, but in some cases it is difficult to know whether or not a Line meets the StringTransformer's requirements until the transformation is already midway. Side Effects: This method should NOT mutate @line directly, but it MAY mutate the Line's underlying Node structure. (WARNING: If the underlying Node structure IS altered, then this method should NOT be allowed to yield an CannotTransform after that point.) Nr5)rr>rs r7 do_transformzStringTransformer.do_transformrr6 _features_modec#Ktd|jDs td|j|}t |t r4|j }td|jjd||j}|j||D]B}t |t r|j }td||j}|Dyw)z StringTransformer instances have a call signature that mirrors that of the Transformer type. Raises: CannotTransform(...) if the concrete StringTransformer class is unable to transform @line. c3VK|]!}|jtjk(#ywr)rRr,STRING).0rhs r7 z-StringTransformer.__call__..sE499 ,Es')z"There are no strings in this line.zThe string transformer z; does not recognize this line as one that it can transform.z>StringTransformer failed while attempting to transform string.N) anyrQr0r isinstancer#err __class__r1okr)rr>rr match_resultr<r line_results r7__call__zStringTransformer.__call__sEEE!"FG G}}T* lC ()--/N!)$..*A*A)BC;;" " &*,,T>B K+s+!,!2%T%&>>#DJ sC%C')r1r2r3r4r__annotations__r_r`rrr TMatchResultrlistr TResultrrrrrr5r6r7rrs4*He)3C3D3T3  T  l      *.s) '$-   (""%/%8"AE" $"r6rc&eZdZUdZeed<eed<y) CustomSplitaA custom (i.e. manual) string split. A single CustomSplit instance represents a single substring. Examples: Consider the following string: ``` "Hi there friend." " This is a custom" f" string {split}." ``` This string will correspond to the following three CustomSplit instances: ``` CustomSplit(False, 16) CustomSplit(False, 17) CustomSplit(True, 16) ``` has_prefix break_idxN)r1r2r3r4r`rr_r5r6r7rr7s(Nr6rceZdZUdZeeZeee ee dffe d<e de de fdZde dee ddfd Zde dee fd Zde defd Zy) CustomSplitMapMixinz This mixin class is used to map merged strings to a sequence of CustomSplits, which will then be used to re-split the strings iff none of the resultant substrings go over the configured max line length. ._CUSTOM_SPLIT_MAPstringr:ct||fS)z Returns: A unique identifier that is used internally to map @string to a group of custom splits. )id)rs r7_get_keyzCustomSplitMapMixin._get_key`s6 F##r6 custom_splitsNcV|j|}t||j|<y)zCustom Split Map Setter Method Side Effects: Adds a mapping from @string to the custom splits @custom_splits. N)rtupler)rrrkeys r7add_custom_splitsz%CustomSplitMapMixin.add_custom_splitsis'mmF#&+M&:s#r6cr|j|}|j|}|j|=t|S)aaCustom Split Map Getter Method Returns: * A list of the custom splits that are mapped to @string, if any exist. OR * [], otherwise. Side Effects: Deletes the mapping between @string and its associated custom splits (which are returned to the caller). )rrr)rrrrs r7pop_custom_splitsz%CustomSplitMapMixin.pop_custom_splitsts;mmF#..s3  " "3 'M""r6c@|j|}||jvS)zb Returns: True iff @string is associated with a set of custom splits. )rr)rrrs r7has_custom_splitsz%CustomSplitMapMixin.has_custom_splitss# mmF#d,,,,r6)r1r2r3r4rrrr dictCustomSplitMapKeyrr staticmethodstrrrrrrr`rr5r6r7rrTs Ex%6k3>N8O%O PQ$$!2$$ ; ;*2;*? ;  ;##[0A#(---r6rc eZdZdZdedefdZdedeede e efdZ e dedeede efdZ dedeede efdZd eed ed eegefdeeeffd Ze ded ede d fdZy ) StringMergeraStringTransformer that merges strings together. Requirements: (A) The line contains adjacent strings such that ALL of the validation checks listed in StringMerger._validate_msg(...)'s docstring pass. OR (B) The line contains a string which uses line continuation backslashes. Transformations: Depending on which of the two requirements above where met, either: (A) The string group associated with the target string is merged. OR (B) All line-continuation backslashes are removed from the target string. Collaborations: StringMerger provides custom split information to StringSplitter. r>r:c|j}t|}g}d}||r||}|jtjk(r||dzr||dzjtjk(rd}|}||rF||jtjk7rn%|j ||rd}n|dz }||rF|st |s|j||dz }||r||jtjk(r|dz }||r||jtjk(r.n|jtjk(r{d|jvrm|j||dz }||rT||jtjk(r4|dz }||r'||jtjk(r.n|dz }||r|r t|StdS)NrrEFTrz\ z+This line has no strings that need merging.) rQis_valid_index_factoryrRr,rrgrrfrer$r=) rr>LLis_valid_indexrrkrhcontains_commentis r7rzStringMerger.do_matchs [[/3S!c7D U\\)"37+sQwK$$ 4$) $Q'!uzzU\\1**2a51+/(FA %Q'(0Ed0K"))#.q$S)bgllell.J1HC%S)bgllell.Jell*v/C%%c*q$S)bgllell.J1HC%S)bgllell.JqGS!J n% %EF Fr6rc#K|}|j||}t|tr|j}|j ||}t|tr|j}t|t rWt|t rG|j }|j }td}||_||_t |yt|yw)Nz6StringMerger failed to merge any strings in this line.) )_remove_backslash_line_continuation_charsrr$r_merge_string_groupr#rr0 __cause__) rr>rri rblc_result msg_resultmsg_cant_transformrblc_cant_transformr<s r7rzStringMerger.do_transformsDD n  k2 &"~~'H--hG j" %!}}H k3 'Jz3,G!+!1 "-//"3 ,HN ,?  ('9N $n% %X, sCCc|j}g}|D][}||}|jtjk(s&d|jvs5t |jrK|j |]|s tdS|j}|jj|_ t||||D]2}|j|}|jjdd|_4t|S)a$ Merge strings that were split across multiple lines using line-continuation backslashes. Returns: Ok(new_line), if @line contains backslash line-continuation characters. OR Err(CannotTransform), otherwise. rzKFound no string leaves that contain backslash line continuation characters.rZ)rQrRr,rrer)rfr=racommentscopyrreplacer$)r>rrindices_to_transform string_idx string_leafrinew_string_leafs r7rz6StringMerger._remove_backslash_line_continuation_charss[[!( 8JZ.K  ELL0k///)+*;*;<$++J7 8$  ::< MM..0hb). NJ&ooj9O$3$9$9$A$A&"$MO ! N(|r6c|j}t|}i}|D];}|j||}t|tr&|j |||||<=|s t dS|j}d} d} t|D]m\} } | |vr| } || \} } |j| | | cxkr| | zkr-nn*|j| D]}|j|d`t||| got|S)am Merges string groups (i.e. set of adjacent strings). Each index from `string_indices` designates one string group's first leaf in `line.leaves`. Returns: Ok(new_line), if ALL of the validation checks found in _validate_msg(...) pass. OR Err(CannotTransform), otherwise. zNo string group is mergedrFTr\) rQr _validate_msgrr#_merge_one_string_groupr=rarbrfrgrr$)rr>rrrmerged_string_idx_dictrvresultriprevious_merged_string_idxprevious_merged_num_of_stringsrrhrrms r7rz StringMerger._merge_string_groups@[[/3?A( J((z:G'3'151M1MJ2 ": .  &34 4::<%'")+& } 2GAt**-.*>TUV>W;.  ,+N,/MMN%)$7$7$=ELOOLtODE (D4& 1 2"(|r6rrrcx||j}d}||jddtdtdtffd }g}g}|} d} | s~|| rv|| jtj k(rVt || jj} | dz } | s)|| r!|| jtj k(rVd} d} d } |} || r|| jtj k(r| dz } || j}t |j}d | vrd |vrtjd d |}|||}t|}|j|| z| z|z|zz} || | } | dz } || r!|| jtj k(r| }ttj | }|jrt|j|_|jt| dzd}|D]`}|j!|}|d k\sJd ||t|zd}||r t| nd zdz}|jt#||bttj |jj%|d}|v||z t|j&krO||j)}t+|dz|D]}||j)||j-||n t/|||j1|j|| |fS)aA Merges one string group where the first string in the group is `LL[string_idx]`. Returns: A tuple of `(num_of_strings, leaf)` where `num_of_strings` is the number of strings merged and `leaf` is the newly merged string to be replaced in the new line. z#@@@@@ BLACK BREAKPOINT MARKER @@@@@rFr string_prefixr:c*t|d|vrGt|Dcgc]}||ddz|ddz }}td|D}|s t|}d}|t |dzd}t j d|zdzzd z|}|Scc}w) aStrip @string (i.e. make it a "naked" string) Pre-conditions: * assert_is_leaf_string(@string) Returns: A string that is identical to @string except that @string_prefix has been stripped, the surrounding QUOTE characters have been removed, and any remaining QUOTE characters have been escaped. frrEc3HK|]}tjd|yw)z'.*[\'\"].*(?.make_naked..s$?"IIH*U?s "z(?:(?.make_nakedms "& )m#!1 8!47Q;a15! !L66))C/%75,L -!sBrZrErrz(\{|\})z\1\1z=Logic error while filling the custom string breakpoint cache.N)parentrerrRr,rr(lowerrrr`rfr-rr*rdfindrrchildrenremoverange insert_childr!r)rrrr atom_node BREAK_MARKrrprefix_tracker next_str_idxrcSNSnum_of_stringsSS next_prefixNSSrnon_string_idxS_leaf temp_stringmark_idxbreakpoint_idxrfirst_child_idxrkrs @r7rz$StringMerger._merge_one_string_groupUsTzN)) ; :$$R($ s$ 3$ 3$ P " |,< %%5&r,'7'='=>DDFF A L |,< %%5  ! \*r,/?/D/D /T a NL!''B+B/557Kf}K!7VVJ4R-Ck*J  ! !* -#c)J6>AAv&B A L)\*r,/?/D/D /T.&ellA&  ! !26<<@FLll3v;?R8 ( JJ"'' 3HA  ON O&hZ&@&BCK% VJQNN  Z!H I J5<<)=)=j")MN   *S1C1C-DD"$Z."7"7"9 a@%CsGNN$%".**?KHi5 {00-@{**r6NcdD]}|}d}t|j}||s%|j|jtjt fvsU|j|jt k(rd}n|r t dcS||z }||s|j|jtjt fvrp|j|jd}d}t}d} |j|dD]q} | jtjk7r<| jtjk(rt| |jvr|dz }nt| jr t d cS| dz } t| jj} d | vr t d cS|j| d | vrY| jd|k7rGd | jt!| dzdvsd| jt!| dzdvr t dcSt| |jvs?|dz }t#|jt| sgt dcS| dkrt d| dS|dkDrt d|dSt!|dkDr|dd hk7rt d|dSt%dS)a|Validate (M)erge (S)tring (G)roup Transform-time string validation logic for _merge_string_group(...). Returns: * Ok(None), if ALL validation checks (listed below) pass. OR * Err(CannotTransform), if any of the following are true: - The target string group does not contain ANY stand-alone comments. - The target string is not in a string group (i.e. it has no adjacent strings). - The string group has more than one inline comment. - The string group has an inline comment that appears to be a pragma. - The set of all string prefixes in the string group is of length greater than one and is not equal to {"", "f"}. - The string group consists of raw strings. - The string group would merge f-strings with different quote types and internal quotes. - The string group is stringified type annotations. We don't want to process stringified type annotations since pyright doesn't support them spanning multiple string values. (NOTE: mypy, pytype, pyre do support them, so we can change if pyright also gains support in the future. See https://github.com/microsoft/pyright/issues/4359.) rDFTzMStringMerger does NOT merge string groups which contain stand-alone comments.rFrNrEz.StringMerger does NOT merge multiline strings.rz(StringMerger does NOT merge raw strings.r'"zUStringMerger does NOT merge f-strings with different quote types and internal quotes.z0Cannot merge strings which have pragma comments.rzz,Not enough strings to merge (num_of_strings=z).z!Too many inline string comments (rZzToo many different prefixes ()rrQrRr,rrr=resetCOMMArrr)r(raddrdrr$) r>rincrfound_sa_commentrrnum_of_inline_string_commentsset_of_prefixesrrhrcs r7rzStringMerger._validate_msgs8 CA$ 3DKK@N # A(;(; "@);;q>&&*<<'+$%0 S!# A(;(; "@)  $ J'--b1()%%KK ,# TDyyELL(99 +4DMM0I1Q61 ,LMM a N&tzz288:Ff}FGG    'v JJrNe+4::c&kAo;;djjVq2>>, $x4==(-2-*4==D+BC RSSG# TJ A >~>NbQ  )1 ,34Q3RRTU   ! #B9(D77HKL L$xr6)r1r2r3r4rrrrr_r rrrrrr-rr`rrrr5r6r7rrs&/GT/Gl/Gb*.s) '$- <''$(I' ''R55*.s)5 5nX+t*X+*-X+?Gt ?TX+ sDy X+tdDdcdgdmddr6rc`eZdZdZdedefdZdedeede e efdZ dedeedefdZ y ) StringParenStripperadStringTransformer that strips surrounding parentheses from strings. Requirements: The line contains a string which is surrounded by parentheses and: - The target string is NOT the only argument to a function call. - The target string is NOT a "pointless" string. - The target string is NOT a dictionary value. - If the target string contains a PERCENT, the brackets are not preceded or followed by an operator with higher precedence than PERCENT. Transformations: The parentheses mentioned in the 'Requirements' section are stripped. Collaborations: StringParenStripper has its own inherent usefulness, but it is also relied on to clean up the parentheses created by StringParenWrapper (in the event that they are no longer needed). r>r:c |j}t|}g}d} |dz }|t|k\rn||}|jtj k7r9|j rH|j j r2|j j jtjk(r||dz r4||dz jtjk7st||dz r||dz r`||dz jtjk(s;||dz jtjk(s||dz jtvr8|}t}|j||} ||dz r>||dz } tj ||dz | Dchc]}|jc}vr| jtj"tj$tj&tj(tj tj*tj,tj.tj0tjh vs_| j rU| j jtj2k(r.| jtj4tj6hvr|| r || jtj8k(rt;|| s|| dzrR|| dzjtj,tj0tjtj<hvr4|j?||}|t|dz kr]||dzjtj k(r:|dz }|t|dz kr$||dzjtj k(r:|r tA|StCdScc}w)NrFrErzz+This line has no strings wrapped in parens.)"rQrrdrRr,rrr" simple_stmtrLrCOLONrSr StringParserparsePERCENTSTARATSLASH DOUBLESLASHrWr^AWAITrMfactorrUrVrIrrwrfr$r=) rr>rrrrkrhr string_parsernext_idx before_lpars r7rzStringParenStripper.do_matchls9 [[/3 1HCc"g~c7DyyELL( KK&&KK&&++t/?/??#37+cAg;##uzz1 C!G- cAg&37   EKK/cAg;##uzz1cAg;##'77J)NM$**2z:H cAg& qk ==2cAg;Q$R4TYY$RR#((!JJ!HH!KK!--!MM!KK!,,!KK!JJ!JJ   $**'..33t{{B(--%**ekk1JJx(xL%%3%bl3"(Q,/Bx!|4D4I4I$$JJJJII N5 %%j1 CGaK'BsQwK,<,< ,L1HCCGaK'BsQwK,<,< ,Ly~ n% %ABBa%SsO+rc#XK|j}g}|D]]}t}|j||}d}||dz ||fD]} |j| sd}n|sK|j ||f_|rt |j ||yttdyw)NTrEFz1All string groups have comments attached to them.) rQrrrgextendr$_transform_to_new_liner#r0) rr>rrstring_and_rpar_indicesrrrpar_idxshould_transformrhs r7rz StringParenStripper.do_transforms[[-/( GJ(NM$**2z:H# JN+R\: &&t,(-$    '.. H/EF G #T007NOP P ST sAB*B*A B*r"c|j}|j}|jj|_d}t |D](}||}|j t jk(r|dz n|}t||||dz||j t jk(rtt j||j} ||jt||| |j| |jjt||g} |jj!t| gj#| n||j|}+t|||dzd|S)NrFrE)rQrarrsortedrRr,rrr-rerr!rfpopr setdefaultr ) rr>r"rri previous_idxrkrhlpar_or_rpar_idxr old_commentss r7r!z*StringParenStripper._transform_to_new_linesS[[::< MM..0 12 Cc7D*.))u||*CsQw  (D"\A-=@P*Q RyyELL("5<<C? #$++-bg{3 ,'0044R3["E !!,,R _bAHHV#$++-L $ hbqm4r6N) r1r2r3r4rrrrr_r rrr!r5r6r7rrWsl(iCTiCliCV*.s) '$- 6!!379! !r6rc deZdZUdZej ej ejejejejejejejg Zeed<ededefdZdedefdZdedededfd Zdededefd Zed eedeefd Zy) BaseStringSplittera Abstract class for StringTransformers which transform a Line's strings by splitting them or placing them on their own lines where necessary to avoid going over the configured line length. Requirements: * The target string value is responsible for the line going over the line length limit. It follows that after all of black's other line split methods have been exhausted, this line (or one of the resulting lines after all line splits are performed) would still be over the line_length limit unless we split this string. AND * The target string is NOT a "pointless" string (i.e. a string that has no parent or siblings). AND * The target string is not followed by an inline comment that appears to be a pragma. AND * The target string is not a multiline (i.e. triple-quote) string. STRING_OPERATORSr>r:cy)a BaseStringSplitter asks its clients to override this method instead of `StringTransformer.do_match(...)`. Follows the same protocol as `StringTransformer.do_match(...)`. Refer to `help(StringTransformer.do_match)` for more information. Nr5rs r7do_splitter_matchz$BaseStringSplitter.do_splitter_match;rr6c,|j|}t|tr|S|j}t |dk(s)J|j j dt ||d}|j||}t|tr|S|S)NrE- should only find one match at a time, found r)r0rr#rrdrr1 _validate)rr>rrrrs r7rzBaseStringSplitter.do_matchFs--d3 lC ( %*>"a' ~~&&'(N#$ & '$A& ..z2 gs #Nr6rNc|j}||}|j||}t|j|kr t dS|j rO|j j Dcgc]}|jc}tjtjgk(rt d|jdSt|j||jvr9t|jt|j|r t dSt|jr t dStdScc}w)au Checks that @line meets all of the requirements listed in this classes' docstring. Refer to `help(BaseStringSplitter)` for a detailed description of those requirements. Returns: * Ok(None), if ALL of the requirements are met. OR * Err(CannotTransform), if ANY of the requirements are NOT met. zBThe string itself is not what is causing this line to be too long.z This string (z/) appears to be pointless (i.e. has no parent).ziLine appears to end with an inline pragma comment. Splitting the line could modify the pragma's behavior.z"We cannot split multiline strings.N)rQ_get_max_string_lengthrdrer=rrrRr,rNEWLINErrrr)r$)rr>rrrmax_string_lengthLs r7r3zBaseStringSplitter._validateWs2[[n  77jI {  !%6 6T !!k6H6H6Q6Q%Raff%R LL MMW &  1 123  dkk*% &$-- 7 max_string_length` implies that the target string IS responsible for causing this line to exceed the line length limit. rErZrzNFT)rQrdepthrRr,rLrer.rdrrrEQUAL PLUSEQUALrSreversedrrIrwrgr'r)rr>rrroffsetp_idxPrhNNN has_commentsrmr7s r7r5z)BaseStringSplitter._get_max_string_lengths[[/3a *q. )NE:>"''5::5zA~&,,2!O 5 Avv...#c!f+/)vv$! vv%++u{{EOOUZZPP ! %R %!)_5Dc#d)n,Fyy$44 *q. ):>"Avv#2 #b'JQRN:RzA~&vv$! j1n- Q'66UYY&277ejj+@ aKF'zA~6zA~.33uzzA! c"((m+F  //:? .L# !  c,,,- -F .1TD%:e%CFA#a&jQq1s5z>%:e%CSZ QG c!f*sDD.#D.,D.c*tt|Sr)rr)rUs r7fstring_contains_exprr]Ls " ##r6fstring old_quotec|dk(rdnd}g}d}t|D]?\}}|j||||j|||j|||}A|j||ddj|S)a; Toggles quotes used in f-string expressions that are `old_quote`. f-string expressions can't contain backslashes, so we need to toggle the quotes if the f-string itself will end up using the same quote. We can simply toggle without escaping because, quotes can't be reused in f-string expressions. They will fail to parse. NOTE: If PEP 701 is accepted, above statement will no longer be true. Though if quotes can be reused, we can simply reuse them without updates or escaping, once Black figures out how to parse the new grammar. rrrNrZ)rrfrjoin)r^r_ new_quotepartsprevious_indexrXends r7rrPs!C'SI EN&w/ s W^E23 WU3'// 9EF LL)* 775>r6ceZdZUdZdZeed<dedefdZ dede e de e efdZd ede eeeffd Zd ede eeeffd Zd edeefd Zd ed e dee fdZdeddfdZd ededefdZdeede efdZy)StringSplittera` StringTransformer that splits "atom" strings (i.e. strings which exist on lines by themselves). Requirements: * The line consists ONLY of a single string (possibly prefixed by a string operator [e.g. '+' or '==']), MAYBE a string trailer, and MAYBE a trailing comma. AND * All of the requirements listed in BaseStringSplitter's docstring. Transformations: The string mentioned in the 'Requirements' section is split into as many substrings as necessary to adhere to the configured line length. In the final set of substrings, no substring should be smaller than MIN_SUBSTR_SIZE characters. The string will ONLY be split on spaces (i.e. each new substring should start with a space). Note that the string will NOT be split on a space which is escaped with a backslash. If the string is an f-string, it will NOT be split in the middle of an f-expression (e.g. in f"FooBar: {foo() if x else bar()}", {foo() if x else bar()} is an f-expression). If the string that is being split has an associated set of custom split records and those custom splits will NOT result in any line going over the configured line length, those custom splits are used. Otherwise the string is split as late as possible (from left-to-right) while still adhering to the transformation rules listed above. Collaborations: StringSplitter relies on StringMerger to construct the appropriate CustomSplit objects and add them to the custom split map. MIN_SUBSTR_SIZEr>r:c|j}|j| tdSt|}d}||rv||dzrk||j||dzjgt j t j gk(r)t||t||dzzdk(r|dz }nY||rQ||j|jvs1||jt j k(rt||dk(r|dz }||rt||r|dz }||r ||jt jk7r tdS|}t}|j||}||rt||r|dz }||r%||jt jk(r|dz }||r tdSt|gS) Nz)Line needs to be wrapped in parens first.rrEznot inrzinz"Line does not start with a string.z%This line does not end with a string.)rQrNr=rrRr,rSrr.rrrrrrr$)rr>rrrkrrs r7r0z StringSplitter.do_splitter_matchs [[  ( ( , 8CD D/3 3 sQw'Cr#'{//0UZZ4LLBsG s2cAg;//8; 1HC C sGLLD11 1#w||uzz)BsG $ 1HC # =C#9 1HCc"bgllell&B<= = % !!"j1 # =C#9 1HC # 2c7<<5;;#> 1HC # ?@ @:,r6rc#  !Kjt|dk(s)Jjjdt||d}|jd}t }t |}t|jj}d|vxrt|j}djrtdDdznd dtd dffd } ||dzxr#|dzjtjk(d t f fd j"dzj$d zzdkr+t'd |jdj$yj)|jt+xrt-fdD!|jd t*f!fd } g} | r>!rj/d} | j0} n>t3 z }j5|}|r|jg} dd!cn|} d| |z}!r6 j6s*|||zk(s|j9||k7r | dz } d| |z}|rj9||}t;tj<|}||j?|jA}| ||jC|| jCtE|||z| dzd| r>| Ed{|rj9|t;tj<}||j?|jA}| |||dzr}|dzdD]/}|tG|z }|jtjHk(s/ntK|ks#|dzjtjk(r2|jC|tM||dzdtE|y|jC|tE|jA}tM||dzdtE|y|jC|jNjQ|_'tE|y7w)NrEr2rrFrTc3DK|]}tt|ywr)rdr)r prefix_leafs r7rz.StringSplitter.do_transform..sJ+C $%Js rir:cxrng}t|D]%\}}t|||j|'y)a\ Side Effects: If @line starts with a string operator and this is the first line we are constructing, this function appends the string operator to @new_line and replaces the old string operator leaf in the node structure. Otherwise this function does nothing. N)rbr!rf)rimaybe_prefix_leavesrrnrfirst_string_linestring_op_leavess r7maybe_append_string_operatorszBStringSplitter.do_transform..maybe_append_string_operatorssD7H"2R "+,?"@ -;be[1 , -r6c`j}|jdzz}|rdndz}|z}|S)a; Returns: The max allowed width of the string value used for the last line we will construct. Note that this value means the width rather than the number of characters (e.g., many East Asian characters expand to two columns). r:rEr)rr<)resultends_with_commar>rstring_op_leaves_lengths r7max_last_string_columnz;StringSplitter.do_transform..max_last_string_columns@%%F djj1n $F ?a 1F - -FMr6r:zUnable to split z at such high of a line depth: c3<K|]}|jkywr)r)rcsplitmax_break_widths r7rz.StringSplitter.do_transform..sTFF$$7TscJrtdkDStkDS)z Returns: True iff `rest_value` (the remaining string value from the last split), should be split again. rE)rdr+)rrx rest_valueuse_custom_breakpointssr7more_splits_should_be_madez?StringSplitter.do_transform..more_splits_should_be_made"s, &=)A-- ,/E/GGGr6F))rQrdrr1rerinsert_str_child_factoryr(rr]_get_string_operator_leavessumrrRr,rr_rr<r=rr`allr'rr'_get_break_idxr_normalize_f_stringr-r_maybe_normalize_string_quotesrarfr$rrLr+rrr)"rr>rrrrinsert_str_childrcdrop_pointless_f_prefixrsrstring_line_resultsrzrmax_bidxmaybe_break_idx next_value next_leaf next_line rest_leaf last_line temp_valuerhnon_string_linerrrvrqr{rxr}rrrwr~s"`` @@@@@@@@@@r7rzStringSplitter.do_transforms;[[>"a' ~~&&'(N#$ & '$A& :$$R(/33BzNC"2j>#7#78>>@ $'&=# 6K zN 7 !;;B?  J9IJ JQ N -D -T - :> * Ur*q./A/F/F%++/U     **14::>) Q "2j>#7#7"89JJ<!  ..r*~/C/CD "&  UTmTT"  ^))  HD H H/1(*%&**1-",, )_E-.#'"5"5j("K"* %%' ^%9%9 .0+,0)15. + $JY/%7J"'))&5.0!T%=%=j&%QQ Q ' 3e; &!55j&I U\\:6I Y '  / / : I )) 4   Y '  & &r)} 5%*YZ*@@J % Y)*\'&& "11*fEJz2 # ++I6JJL %i0 *q. )$J:>+, c$i' 99 * *%)?)AAj1n%**ekk9  +ir*q.2B/CDm#  +m#"&**,otR Q8H5IJ))   Y '!%!3!3!5I Y- a 's L)S!9S!>S?B&S!&C9S!rc#Kd}tt|}|D]Z\}}|dk(r| }|r|dk7rd}d}|dz }|D]\}}|dk(s |}n#t|jjd||f\yw)z Yields: All ranges of @string which, if @string were to be split there, would result in the splitting of an \N{...} expression (which is NOT allowed). F\rCrErX LOGIC ERROR!N)iterrb RuntimeErrorrr1)rr previous_was_unescaped_backslashitrkcbeginres r7_iter_nameescape_slicesz&StringSplitter._iter_nameescape_slicess,1( )F# $ FCDy7W3W03qCx380/4 ,!GE NQ8C N#dnn&=&=%>m#LMM* % s AA9 0A9c#nKdt|jvryt|Ed{y7w)z Yields: All ranges of @string which, if @string were to be split there, would result in the splitting of an f-expression (which is NOT allowed). rN)r(rr)rrs r7_iter_fexpr_slicesz!StringSplitter._iter_fexpr_slicess0 '/557 7 #F+++s +535ct}|j||j|g}|D]'}|D] \}}|jt ||")|Sr)rrrupdater)rrillegal_indices iteratorsrrres r7_get_illegal_split_indicesz)StringSplitter._get_illegal_split_indicessm&)e  # #F +  ( ( 0  :B  : s&&uUC'89 : :r6 max_break_idxct|sJtjdtdtffd dtdtffd }|}|dz r!||s|dz}|dz r ||s||sB|dz}|dzr!||s|dz }|dzr ||s|r||sy|S)a This method contains the algorithm that StringSplitter uses to determine which character to split each string at. Args: @string: The substring that we are attempting to split. @max_break_idx: The ideal break index. We will return this value if it meets all the necessary conditions. In the likely event that it doesn't we will try to find the closest index BELOW @max_break_idx that does. If that fails, we will expand our search by also considering all valid indices ABOVE @max_break_idx. Pre-Conditions: * assert_is_leaf_string(@string) * 0 <= @max_break_idx < len(@string) Returns: break_idx, if an index is able to be found that meets all of the conditions listed in the 'Transformations' section of this classes' docstring. OR None, otherwise. rr:c |vS)z Returns: True iff returning @i would result in the splitting of an unsplittable expression (which is NOT allowed). r5)r_illegal_split_indicess r7breaks_unsplittable_expressionzEStringSplitter._get_break_idx..breaks_unsplittable_expressions .. .r6cL |dk(}|dz xr |dz tv}d}|dz }|r! |dk(r| }|dz}|r |dk(rt |djk\xrt d|jk\}|xs|xr|xr |xr | S)z Returns: True iff ALL of the conditions listed in the 'Transformations' section of this classes' docstring would be met by returning @i.  rETrN)SPLIT_SAFE_CHARSrdri) ris_space is_split_safeis_not_escapedrZ is_big_enoughrrrrs r7passes_all_checksz8StringSplitter._get_break_idx..passes_all_checks s ayC'H*1q51WfQUmGW6WM!NAA #q T(9%3!3Q!#q T(9 F12J4#7#77<r Ot';';;  *]:":!:7q99  r6rEN)rr&rIndexr`)rrrrrrrrs`` @@@r7rzStringSplitter._get_break_idxs007m,,,f%!%!@!@!H /e / /  4  6" Y]+4Ei4P NIY]+4Ei4P!+ &)I Q/8I)8TQ !Q/8I)8T"),4Ei4Pr6rhNcR|jrt|j|_yyr)rr*re)rrhs r7rz-StringSplitter._maybe_normalize_string_quotes8s  ! !0R0J#f+-(D66'3-D66'3-DJ \*. .Mr6rQclt|}g}d}||j|jtjgzvrwt ||jt ||j}|j||dz }||j|jtjgzvrw|S)NrrE) rrRr.r,rSr-rstriprf)rrQrrrrrns r7rz*StringSplitter._get_string_operator_leavesWs &\ ejjD11UZZL@@r!uzz3r!u:+;+;+=>K  # #K 0 FAejjD11UZZL@@ r6)r1r2r3r4rirrrrr0rr_r rrrrrrrrrrrr-rrrrr5r6r7rgrghs#JOU4 d4 |4 lf f *.s)f '$- f PchuUE\?R6S> , ,%u :M1N ,  U SSSS#Sj=4=D=#ss6  (4.  T$Z  r6rgceZdZdZdedefdZedee de e fdZ edee de e fdZ edee de e fdZedee de e fd Zedee de e fd Zded ee deeefd Zy )StringParenWrappera/ StringTransformer that wraps strings in parens and then splits at the LPAR. Requirements: All of the requirements listed in BaseStringSplitter's docstring in addition to the requirements listed below: * The line is a return/yield statement, which returns/yields a string. OR * The line is part of a ternary expression (e.g. `x = y if cond else z`) such that the line starts with `else `, where is some string. OR * The line is an assert statement, which ends with a string. OR * The line is an assignment statement (e.g. `x = ` or `x += `) such that the variable is being assigned the value of some string. OR * The line is a dictionary key assignment where some valid key is being assigned the value of some string. OR * The line is an lambda expression and the value is a string. OR * The line starts with an "atom" string that prefers to be wrapped in parens. It's preferred to be wrapped when it's is an immediate child of a list/set/tuple literal, AND the string is surrounded by commas (or is the first/last child). Transformations: The chosen string is wrapped in parentheses and then split at the LPAR. We then have one line which ends with an LPAR and another line that starts with the chosen string. The latter line is then split again at the RPAR. This results in the RPAR (and possibly a trailing comma) being placed on its own line. NOTE: If any leaves exist to the right of the chosen string (except for a trailing comma, which would be placed after the RPAR), those leaves are placed inside the parentheses. In effect, the chosen string is not necessarily being "wrapped" by parentheses. We can, however, count on the LPAR being placed directly before the chosen string. In other words, StringParenWrapper creates "atom" strings. These can then be split again by StringSplitter, if necessary. Collaborations: In the event that a string line split by StringParenWrapper is changed such that it no longer needs to be given its own line, StringParenWrapper relies on StringParenStripper to clean up the parentheses it created. For "atom" strings that prefers to be wrapped in parens, it requires StringSplitter to hold the split until the string is wrapped in parens. r>r:ch|j}|jdjtvr tdS|j |xs]|j |xsJ|j |xs7|j|xs$|j|xs|j|}||j|j}td|DsI|j|jdzdzz }t||kDr|j|s tdSt!|gStdS)NrFzACannot wrap parens around a line that ends in an opening bracket.c3:K|]}|dk(xs|tvyw)rN)r)rchars r7rz7StringParenWrapper.do_splitter_match..s'<@ 7t'777srEr:zWe do not wrap long strings in parentheses when the resultant line would still be over the specified line length and can't be split further by StringSplitter.z2This line does not contain any non-atomic strings.)rQrRrr= _return_match _else_match _assert_match _assign_match_dict_or_lambda_matchrNrerrr<r+rr$)rr>rr string_valuemax_string_widths r7r0z$StringParenWrapper.do_splitter_matchsG [[ ;;r?  #3 3S    r " 1# 1!!"% 1!!"% 1))"-  1 ,,R0   !;;z288LDP$(#3#3 Q!7K#L \*-==11,?#T  zl# #HIIr6rc t|dtjtjfvr`|djdvrOt |}|drt |drdnd}||r"||jtjk(r|Sy)aK Returns: string_idx such that @LL[string_idx] is equal to our target (i.e. matched) string, if this line matches the return/yield statement requirements listed in the 'Requirements' section of this classes' docstring. OR None, otherwise. r)r:yieldrErzN) r r" return_stmt yield_exprrerrrRr,rrrrks r7rz StringParenWrapper._return_matchs r!u $"2"2DOO!D D J %&J'4B7N%a(\"Q%-@!aCc"r#w||u||'C r6cDt|dtjk(r|djtj k(ra|dj dk(rOt|}|drt|drdnd}||r"||jtjk(r|Sy)aG Returns: string_idx such that @LL[string_idx] is equal to our target (i.e. matched) string, if this line matches the ternary expression requirements listed in the 'Requirements' section of this classes' docstring. OR None, otherwise. relserErzN) r r"testrRr,rSrerrrrs r7rzStringParenWrapper._else_matchs 1 $)) +1 ejj(1 v%3B7N%a(\"Q%-@!aCc"r#w||u||'C r6ct|dtjk(r|djdk(rt |}t |D]\}}|j tjk(s$t||dzr|dzn|dz}||sH||j tjk(si|}t}|j||}||r|cSy)aE Returns: string_idx such that @LL[string_idx] is equal to our target (i.e. matched) string, if this line matches the assert statement requirements listed in the 'Requirements' section of this classes' docstring. OR None, otherwise. rassertrErzN) r r" assert_stmtrerrbrRr,rrrrrrrrrhrkrrs r7rz StringParenWrapper._assert_matchs r!u !1!1 1bekkX6M3B7N$R= .499 +#/1q5 #:!a%AC&c*r#w||u||/K%( )5 +11"jA .c2#-- ."r6ct|dtjtjtjfvr'|dj t jk(rt|}t|D]\}}|j t jt jfvs3t||dzr|dzn|dz}||sW||j t jk(sx|}t}|j||}t|dtjk(r-||r%||j t j k(r|dz }||r|cSy)aI Returns: string_idx such that @LL[string_idx] is equal to our target (i.e. matched) string, if this line matches the assignment statement requirements listed in the 'Requirements' section of this classes' docstring. OR None, otherwise. rrErzN)r r" expr_stmtargumentpowerrRr,rSrrbr=r>rrrrrrs r7rz StringParenWrapper._assign_matchs" 1 4>>4==$**"M M1 ejj(3B7N$R= .499eoo >>#/1q5 #:!a%AC&c*r#w||u||/K%( )5 +11"jA (1.$--? .s 3 "3  ;1HC .c2#--1 .4r6clt|dt|djg}tj|vstj|vrt |}t |D]\}}|jtjk(s$|t|dz ks6t||dzr|dzn|dz}||sZ||jtjk(s{|}t}|j||}||r%||jtjk(r|dz }||r|cSy)am Returns: string_idx such that @LL[string_idx] is equal to our target (i.e. matched) string, if this line matches the dictionary key assignment statement or lambda expression requirements listed in the 'Requirements' section of this classes' docstring. OR None, otherwise. rrErzN)r rr"rHlambdefrrbrRr,rrdrrrrr)r parent_typesrrrhrkrrs r7rz(StringParenWrapper._dict_or_lambda_matchIs$BqE*K1 ,EF    , 0L3B7N$R= .499 +CGaK#/1q5 #:!a%AC&c*r#w||u||/K%( )5 +11"jA*#.2c7<<5;;3N1HC .c2#--' .*r6rc#K|j}t|dk(s)J|jjdt||d}t |}t ||}d}d}||j tjk(rd}||g} |r| j|||j} |d|} d} | rF| dj tjk(r&d} | j| d| jt| || ttjd} | rt||dz | n|| | j| | D]+}|j!|D]}| j|d-t#| ||j$}t'|j(|j*dzd|j,|j. }ttj0|}|||j|d}||dzr||dzd}|r|j| rA|r |dj tj2k(sJd | d |d |j}n|r|dj tj2k(r|dj4}|w|| vrs| j7|}d|cxkrt| dz krKnnH| |dz j tj8k(r%| |dzj$d k(r|jt|||t#||j}| j:|_ttj2d }| t||n|||j||r:ttjd}t||||j|t#|yw)NrEr2rrFFTrr\)r@r<inside_bracketsshould_split_rhsmagic_trailing_commaz8Apparently, old parentheses do NOT exist?! (left_leaves=z, right_leaves=rr[,)rQrdrr1rrrRr,rrfrarLr'rr-r!rgr$rerr@r<rrrrIopening_bracketrBrbracket_tracker)rr>rrrrr comma_idxrvleaves_to_steal_comments_from first_line left_leavesold_parens_exist lpar_leafrhrmr string_liner old_rpar_leaf right_leavesrrBr new_rpar_leaf comma_leafs r7rzStringParenWrapper.do_transformps[[>"a' ~~&&'(N#$ & '$A& /33BzNC  i=   ,"O)+J(8%  ) 0 0I ?ZZ\ *o ! ;r?//5::=#  ) 0 0R A OO j$ 4S)  "Z!^,i 8 Y ')$ 2 CD $ 3 3D 9 C !!,T!B C Cn *~++ **q. !22!%!:!:  5<<6 %;' *q. )j1n./L  "# R(8(=(=(K%%0MaQK!- 0 0 2 ,r"2"7"75::"E#/r"2"B"B".?k3Q'--o>EE8C $4q$88' 2775;;F' 288HD$((* +t\ :oJJL $.$>$> !UZZ-  $ - 7 ] +' ekk3/J "Y- 4   Z (msO.O0N)r1r2r3r4rrr0rrr-rr_rrrrrr rrr5r6r7rrcs"7r$Jd$J|$JL$t*#0T x}4 $t* #  D,$t*,#,,\$$t*$#$$Lyy*.s)y '$- yr6rceZdZUdZdZeed<dZeed<dZeed<dZ eed <d Z eed <d Z eed <dZ eed<dZ eed<dZeed<eejfeeejfe eefeeejfe e ejfe e efee ejfe e efe e efee efei Zeeeeefefed<ddZdeededefdZdedefdZy)ra A state machine that aids in parsing a string's "trailer", which can be either non-existent, an old-style formatting sequence (e.g. `% varX` or `% (varX, varY)`), or a method-call / attribute access (e.g. `.format(varX, varY)`). NOTE: A new StringParser object MUST be instantiated for each string trailer we need to parse. Examples: We shall assume that `line` equals the `Line` object that corresponds to the following line of python code: ``` x = "Some {}.".format("String") + some_other_string ``` Furthermore, we will assume that `string_idx` is some index such that: ``` assert line.leaves[string_idx].value == "Some {}." ``` The following code snippet then holds: ``` string_parser = StringParser() idx = string_parser.parse(line.leaves, string_idx) assert line.leaves[idx].type == token.PLUS ``` ic4 DEFAULT_TOKENrESTARTrzrwr;rSr:rSINGLE_FMT_ARGrhrLrIDONE_gotor:Nc4|j|_d|_y)Nr)r_state_unmatched_lpars)rs r7rzStringParser.__init__0 sjj !r6rQrc||jtjk(sJ|dz}|t|kr<|j ||r(|dz }|t|kr|j ||r(|S)a3 Pre-conditions: * @leaves[@string_idx].type == token.STRING Returns: The index directly after the last leaf which is a part of the string trailer, if a "trailer" exists. OR @string_idx + 1, if no string "trailer" exists. rE)rRr,rrd _next_state)rrQrrks r7rzStringParser.parse4 stj!&&%,,6661nCKD$4$4VC[$A 1HCCKD$4$4VC[$A r6rhct|ry|j}|tjk(r|xjdz c_|j }||jk(rI|tj k(r5|xjdzc_|jdk(r|j |_y||f|jvr|j||f|_n]||jf|jvr!|j||jf|_n"t|jjd|j |jk(ryy)a Pre-conditions: * On the first call to this function, @leaf MUST be the leaf that was directly after the string leaf in question (e.g. if our target string is `line.leaves[i]` then the first call to this method must be `line.leaves[i + 1]`). * On the next call to this function, the leaf parameter passed in MUST be the leaf directly following @leaf. Returns: True iff @leaf is a part of the string's trailer. TrErrF) rrRr,rLrrrIrrrrr1r)rrh next_token current_states r7rzStringParser._next_stateF s  YY  #  ! !Q & !  DII %UZZ'%%*%((A-"&))DK(z*djj8"jj )BC "4#5#56$**D"&**]D.insert_str_child s9(((+++""#3U;Ar6)rrLN)rrrrs @@r7rrz s;\ &&M"))+t r6seqc,dtdtffd }|S)a Examples: ``` my_list = [1, 2, 3] is_valid_index = is_valid_index_factory(my_list) assert is_valid_index(0) assert is_valid_index(2) assert not is_valid_index(3) assert not is_valid_index(-1) ``` rkr:c6d|cxkxrtkScS)zx Returns: True iff @idx is positive AND seq[@idx] does NOT raise an IndexError. r)rd)rkrs r7rz.is_valid_index_factory..is_valid_index s C"#c(""""r6)r_r`)rrs` r7rr s #C#D# r6)cr4rabcrr collectionsrcollections.abcrrrr r dataclassesr typingr r rrrrrmypy_extensionsrblack.commentsr black.linesrr black.moderr black.nodesrrrrrrrr r!r" black.rustyr#r$r% black.stringsr&r'r(r)r*r+blib2to3.pgen2r,blib2to3.pytreer-r. Exceptionr0r8r Transformerr_rrrStringIDrrr frozensetrrr=rnrr`rHrKrqrrrrrrrr-rr]rrgrrrrr5r6r7rs ##NN!JJJ!2+$   ('!&8i8  CL 4:j148(4.HI     O# $tE{# ;<##o.@ @$W-@59@ d^@FSc#hSW, (+C 4$t**ggT  2(C-(9-9-9-xC$&9CL|+|~D*DN,,sCx 9,^$S$T$###0x ')<x vF+-@FR KK\:$:8RD$J3G:z (C5$;2Gr6