o ]Lbr @sddlmZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z mZmZedZdd eDZd d eDZd d ZdJddZdJddZddZddZddZddZdKddZdLddZdd Zd!d"Zd#d$Zd%d&Z e j!dd'Gd(d)d)e"Z#d*d+Z$d,d-Z%d.d/Z&e'd0Z(d1d2Z)dMd4d5Z*d6d7Z+d8d9Z,d:d;Z-dd?a/dNdAdBZ0dddddd d d d d dC Z1dDdEZ2dFdGZ3dHdIZ4dS)O)absolute_importN)_)attr)encodingerrorpycompats()[]{}?*+-|^$\.&~# cCs i|] }t|d|dqS)\latin1)orddecode.0irs rcCsi|]}|d|qS)r rr rrrrscCs8d}t|trd}|d}|t}|r|S|dS)z"Drop-in replacement for re.escape.TFr ) isinstancebytesr translate_regexescapemapencode)patwantunirrrreescape"s    rFcCsdt||||dS)zPretty print an object.bprefixindentlevel)join pprintgen)orrrrrrpprint1sr#c cst|tr|rdt|VdSdt|VdSt|tr*dtt|VdSt|tr|s6dVdSdV|rI|d7}dVd ||Vt|D]*\}}t||||d D]}|VqY|dt|krw|rtd Vd ||VqMd VqM|r|d8}dVd ||Vd VdSt|tr |sdVdSdV|r|d7}dVd ||Vtt | D]=\}\}}t||||d D]}|VqdVt||||d D]}|Vq|dt|kr|rd Vd ||Vqd Vq|r|d8}dVd ||VdVdSt|t rw|sdVdSdV|r+|d7}dVd ||Vtt |D]/\}}t||||d D]}|Vq=|dt|kr_|r\d Vd ||Vq1d Vq1|rr|d8}dVd ||VdVdSt|t r|sdVdSdV|r|d7}dVd ||Vt|D]/\}}t||||d D]}|Vq|dt|kr|rd Vd ||Vqd Vq|r|d8}dVd ||VdVdSt|t jrizt|} WntydVYdSwdV|r|d7}dVd ||Vd} | sS| } zt|} Wn ty,d} Ynwt| |||d D]}|Vq5| sP|rMd Vd ||Vnd V| r|rd|d8}dVd ||Vd VdSt|VdS)aPretty print an object to a generator of atoms. ``bprefix`` is a flag influencing whether bytestrings are preferred with a ``b''`` prefix. ``indent`` controls whether collections and nested data structures span multiple lines via the indentation amount in spaces. By default, no newlines are emitted. ``level`` specifies the initial indent level. Used if ``indent > 0``. sb'%s's'%s'sbytearray['%s']s[]N[  rs, s, ]s{}{s: }sset([])sset([s])s()()sgen[]sgen[FT)rr escapestr bytearraylist enumerater!lendictsorteditemssettupletypes GeneratorTypenext StopIterationrbyterepr) r"rrrrachunkkvnextitemlastcurrentrrrr!6s(                   r!cCsg}t|}d}}|t|krtd}|d|d}|dkr$t|}n||dkr=|d|dr=|d|d|d}|dkrD|}n|d7}|dd||dd|}|dks\J|||||f||}}|t|ksd d d |DS) z9Pretty print a representation of a possibly-nested objectrr&css |] \}}d||VqdS)s Nr)rlsrrr szprettyrepr..) rr;r1find startswithrfindcountappendrstripr )r"linesrsp0p1q0q1rGrrr prettyreprs&      rVcCsX|durdSt|tr|dttj|ddSt|tr!|St|r(|St|S)arFormat an optional printable representation from unexpanded bits ======== ================================= type(r) example ======== ================================= tuple ('', other) bytes '' callable lambda: '' % sorted(b) object other ======== ================================= Nrrr%)rr6rrapply maybebytestrrcallabler#)rrrr buildreprs   r[cCst|od|vS)z&return true if a string is binary data)boolrHrrrbinary5r_cCs<|dr d|ddfS|drd|ddfSd|fS)Nsre:resliteral:literal)rK)patternrrr _splitpattern:s  rfTc st|\}}|dkr8zd}|stj}t||}Wntjy1}z ttdt|d}~ww|||jfS|dkrR|rB|j }n t |fdd}|||fSt d|) a accepts a string, possibly starting with 're:' or 'literal:' prefix. returns the matcher name, pattern, and matcher function. missing or unknown prefixes are treated as literal matches. helper for tests: >>> def test(pattern, *tests): ... kind, pattern, matcher = stringmatcher(pattern) ... return (kind, pattern, [bool(matcher(t)) for t in tests]) >>> def itest(pattern, *tests): ... kind, pattern, matcher = stringmatcher(pattern, casesensitive=False) ... return (kind, pattern, [bool(matcher(t)) for t in tests]) exact matching (no prefix): >>> test(b'abcdefg', b'abc', b'def', b'abcdefg') ('literal', 'abcdefg', [False, False, True]) regex matching ('re:' prefix) >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar') ('re', 'a.+b', [False, False, True]) force exact matches ('literal:' prefix) >>> test(b'literal:re:foobar', b'foobar', b're:foobar') ('literal', 're:foobar', [False, True]) unknown prefixes are ignored and treated as literals >>> test(b'foo:bar', b'foo', b'bar', b'foo:bar') ('literal', 'foo:bar', [False, False, True]) case insensitive regex matches >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar') ('re', 'A.+b', [False, False, True]) case insensitive literal matches >>> itest(b'ABCDEFG', b'abc', b'def', b'abcdefg') ('literal', 'ABCDEFG', [False, False, True]) rarinvalid regular expression: %sNrccst|kS)N)rlowerr^ipatrryszstringmatcher..unhandled pattern kind: %s) rfremodIcompiler ParseErrorr forcebytestrsearch__eq__rrhProgrammingError)re casesensitivekindflagsregexematchrrir stringmatcherBs* &    r{c Cs|t|\}}|dkr*zt||WStjy)}z ttdt|d}~ww|dkr7tt||Std|)aBuild a regexp object from a string pattern possibly starting with 're:' or 'literal:' prefix. helper for tests: >>> def test(pattern, *tests): ... regexp = substringregexp(pattern) ... return [bool(regexp.search(t)) for t in tests] >>> def itest(pattern, *tests): ... regexp = substringregexp(pattern, remod.I) ... return [bool(regexp.search(t)) for t in tests] substring matching (no prefix): >>> test(b'bcde', b'abc', b'def', b'abcdefg') [False, False, True] substring pattern should be escaped: >>> substringregexp(b'.bc').pattern '\\.bc' >>> test(b'.bc', b'abc', b'def', b'abcdefg') [False, False, False] regex matching ('re:' prefix) >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar') [False, False, True] force substring matches ('literal:' prefix) >>> test(b'literal:re:foobar', b'foobar', b're:foobar') [False, True] case insensitive literal matches >>> itest(b'BCDE', b'abc', b'def', b'abcdefg') [False, False, True] case insensitive regex matches >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar') [False, False, True] rargNrcrl) rfrmrorrprrqescapert)rerwrvryrrrsubstringregexps &r}cCs|d}|dkr|d|}|d}|dkr ||dd}|d}|dkr/|d|}|d}|dkr>|d|}|S)z>Return a short representation of a user name or email address.@rNrDr%r'.rJuserfrrr shortusers       rcCsD|d}|dkr|d|}|d}|dkr ||dd}|S)z,Return the user portion of an email address.r~rNrDr%rrrrr emailusers   rcCs,|d}|dkr d}||dd|S)zget email of author.rFrCNrDr%r)authorrZrrremails rcCsVd|vr|S|d}|dkr|d|dddS|d}|d|dd S) aReturns the name before an email address, interpreting it as per RFC 5322 >>> person(b'foo@bar') 'foo' >>> person(b'Foo Bar ') 'Foo Bar' >>> person(b'"Foo Bar" ') 'Foo Bar' >>> person(b'"Foo "buz" Bar" ') 'Foo "buz" Bar' >>> # The following are invalid, but do exist in real-life ... >>> person(b'Foo "buz" Bar ') 'Foo "buz" Bar' >>> person(b'"Foo Bar ') 'Foo Bar' r~rDrCNs "s\""rr')rJstripreplace)rrrrrpersons  r)hashc@s$eZdZdZeZejddZdS) mailmappingz>Represents a username/email key or value in a mailmap fileN)default)__name__ __module__ __qualname____doc__ribrnamerrrrrsrcCs| p | o t|dkS)auReturns True if the parsed names and emails in a mailmap entry are invalid. >>> # No names or emails fails >>> names, emails = [], [] >>> _ismailmaplineinvalid(names, emails) True >>> # Only one email fails >>> emails = [b'email@email.com'] >>> _ismailmaplineinvalid(names, emails) True >>> # One email and one name passes >>> names = [b'Test Name'] >>> _ismailmaplineinvalid(names, emails) False >>> # No names but two emails passes >>> names = [] >>> emails = [b'proper@email.com', b'commit@email.com'] >>> _ismailmaplineinvalid(names, emails) False r)r1)namesemailsrrr_ismailmaplineinvalidsrcCsi}|dur|S|D]t}|drq gg}}g}|D]6}|dr*n.|drR|drR||dd|rI|d|g}t|dkrQnq!||q!t||r^q t |dt|dkrl|dndd }t |d |rz|d ndd ||<q |S) axParses data in the .mailmap format >>> mmdata = b"\n".join([ ... b'# Comment', ... b'Name ', ... b' ', ... b'Name ', ... b'Name Commit ', ... ]) >>> mm = parsemailmap(mmdata) >>> for key in sorted(mm.keys()): ... print(key) mailmapping(email='commit1@email.xx', name=None) mailmapping(email='commit2@email.xx', name=None) mailmapping(email='commit3@email.xx', name=None) mailmapping(email='commit4@email.xx', name='Commit') >>> for val in sorted(mm.values()): ... print(val) mailmapping(email='commit1@email.xx', name='Name') mailmapping(email='name@email.xx', name=None) mailmapping(email='proper@email.xx', name='Name') mailmapping(email='proper@email.xx', name='Name') N#rDrFr%rCr'r)rrr) splitlineslstriprKsplitendswithrNr r1rr)mailmapcontentmailmaplinerr namebuilderelement mailmapkeyrrr parsemailmaps>        rc Cst|r|s|Stt|t|d}z||}Wnty0t|jd}||tdd}Ynwd|jr8|jn|j|jrB|jfS|jfS)a.Returns the author field according to the mailmap cache, or the original author field. >>> mmdata = b"\n".join([ ... b'# Comment', ... b'Name ', ... b' ', ... b'Name ', ... b'Name Commit ', ... ]) >>> m = parsemailmap(mmdata) >>> mapname(m, b'Commit ') 'Name ' >>> mapname(m, b'Name ') 'Name ' >>> mapname(m, b'Commit ') 'Name ' >>> mapname(m, b'Commit ') 'Name ' >>> mapname(m, b'Unknown Name ') 'Unknown Name ' )rr)rNs%s <%s>)isauthorwellformedrrrKeyErrorgetr)rrcommitpropercommit2rrrmapnamehs     rs^[^<]+\s<[^<>]+@[^<>]+>$cCst|duS)a&Return True if the author field is well formed (ie "Contributor Name ") >>> isauthorwellformed(b'Good Author ') True >>> isauthorwellformed(b'Author ') True >>> isauthorwellformed(b'Bad Author') False >>> isauthorwellformed(b'Bad Author >> isauthorwellformed(b'Bad Author author@author.com') False >>> isauthorwellformed(b'') False >>> isauthorwellformed(b'Bad Author ') False N)_correctauthorformatrz)rrrrrsrcCstj||ddS)zCTrim string to at most maxlength (default: 400) columns in display.s...)ellipsis)rtrim)text maxlengthrrrrr`rcCs t|tr t|}t|dSNr)r memoryviewrcodecs escape_encoder^rrrr-s r-cCst|dSr)r escape_decoder^rrr unescapestrsrc Cs4zt|WStyttt|YSw)zLPortably format an arbitrary object (e.g. exception) into a byte string.)rbytestrUnicodeEncodeErrorr strtolocalstr)objrrrrqs   rqcCstt|ddS)Ns\\r )rr;rrr^rrruireprsrcKs$Gdddtj}|a|di|S)Nc@s(eZdZdZddZddZddZdS) z_MBTextWrapper..twa8 Extend TextWrapper for width-awareness. Neither number of 'bytes' in any encoding nor 'characters' is appropriate to calculate terminal columns for specified string. Original TextWrapper implementation uses built-in 'len()' directly, so overriding is needed to use width information of each characters. In addition, characters classified into 'ambiguous' width are treated as wide in East Asian area, but as narrow in other. This requires use decision to determine width of such characters. cSsZd}tj}tt|D]}||||7}||kr(|d|||dfSq |dfS)Nrr)r ucolwidthrxranger1)selfucstr space_leftrGcolwidthrrrr_cutdownsz#_MBTextWrapper..tw._cutdowncSsXt||d}|jr||d|\}}||||d<dS|s*||dSdS)Nr%rC)maxbreak_long_wordsrrNpop)rreversed_chunkscur_linecur_lenwidthrcutresrrr_handle_long_words  z,_MBTextWrapper..tw._handle_long_wordc Sstj}g}|jdkrtd|j||rg}d}|r!|j}n|j}|jt|}|jr;|d dkr;|r;|d=|rX||d}|||krU| | ||7}nn|s=|rj||d|krj| |||||jrz|rz|d dkrz|d=|r| |d ||s|S)Nrsinvalid width %r (must be > 0)rC)rrr ValueErrorreversesubsequent_indentinitial_indentr1drop_whitespacerrNrrr ) rchunksrrPrrrrrGrrr _wrap_chunkssB    3z'_MBTextWrapper..tw._wrap_chunksN)rrrrrrrrrrrtws  rr)textwrap TextWrapper_MBTextWrapper)kwargsrrrrrsgrrcCstt|t|}||krtd|d}|ttjttj}|ttjttj}|ttjttj}t|||d}|| ttjS)NNr%)rrr) rr1r rsysstrr encodingmoderfillr)rr initindent hangindent maxindentwrapperrrrwrap>s&      r) 1syesstruesonsalways0snosfalsesoffsnevercCst|dS)zLParse s into a boolean. If s is not a valid boolean, returns None. N) _booleansrrhr^rrr parseboolcsrcsVfddfddfdd|dur%t|tr%|d}n|}|p*gS) zparse a configuration value as a list of comma/space separated strings >>> parselist(b'this,is "a small" ,test') ['this', 'is', 'a small', 'test'] csJd}|t|kr<|||ds|||ddkr._parse_plaincs|t|krV|||ddkrV|d|d7}|t|krQ|||ds3|||ddkrQ|d7}|t|krQ|||ds3|||ddks3||fS|t|kr|||ddkr|||ddkr|dt|kr||d|ddkr|d7}|dd7<n|d|||d7<|d7}|t|kr|||ddksf|t|krވ|d}|sd|d<nd|d|d<|dd}||d||fS|d7}|t|kr |||dd vr |d7}|t|kr |||dd vs|t|kr7|dt|kr1|||ddkr1|dd7<|d7}n |dnd||fS||fS) Nr%rrrr rrCr)r'r)r1rNrextend)rrHr real_parts) _configlistrrrrsR           $"(    zparselist.._parse_quotecsB|d}|s gSdgd}}}|r||||\}}}|s|S)Ns ,rr)rO)rHparserrr)rrrrs zparselist.._configlistNs , )rrr)valueresultr)rrrr parselistks 0 rcCs tjr t|dSt|S)z8Evaluate a string containing a Python literal expressionr )rispy3ast literal_evalr r^rrrevalpythonliterals r)Frr)T)r)r)rr)5 __future__rrrrermrr7i18nr thirdpartyrrrrrr _respecialrregexbytesescapemaprr#r!rVr[r_rfr{r}rrrrrHobjectrrrrrorrrr-rrqrrrrrrrrrrrsl      I  =4  S 0   l Z