o k` @s(ddlZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlZddlmZmZmZmZddlmZmZmZmZmZdddZdddZ ej!dkr|dd l"m#Z#nddl$Z$d d Z#ze%Z%Wne&yGd d d e'Z%YnwddZ(e )dd*e+dde,e-e.ddZ/ddZ0dZ1ej!dkrddZ2ddZ3z-ddl4Z4dZ5dZ6e4j7j8j9Z:ddZ2e4j7j;jZ?e4j7j8j@Z@dZ1d d!Z3Wn eAyYnwd"d#ZBnejBZBdZ1Gd$d%d%eCZDdd)d*ZEdd,d-ZFd.d/ZGej!dkr*d0d1ZHnd2d1ZHd3d4ZI  dd5d6ZJd7d8ZKGd9d:d:eCZLd;d<ZMdd=d>ZNdgdfd?d@ZOdAdBZPGdCdDdDeCZQdEdFZRdGdHZSdIdJZTe )dKZUddLdMZVdNdOZWdPdQZXdRdSZYdTdUZZe[gdVZ\dWdXZ]dYdZZ^d[d\Z_d]d^Z`d_d`Zaz ebdaejbZbWnecye dZedbdcZbYnwddedfZfddhdiZgddkdlZhGdmdndneCZidodpZjGdqdrdreCZke )dsZldtduZmddvdwZndxdyZoddzd{Zpdd|d}Zqdd~dZrddZsdddZtddZudZvdS)N)time_now to_datetime to_timestamputc)exception_to_unicodegetpreferredencodingstripws to_unicodeto_utf8cCs^|jr|jS|r|j|}|r|S|jd}|jd}|r(|r(d||fS|p.|p.|jS)aGet most informative "reporter" identity out of a request. That's the `Request`'s authname if not 'anonymous', or a `Request` argument, or the session name and e-mail, or only the name or only the e-mail, or 'anonymous' as last resort. :param req: a `trac.web.api.Request` :param arg_name: if given, a `Request` argument which may contain the id for non-authentified users nameemailz%s <%s>)is_authenticatedauthnameargsgetsession)reqarg_namerr r r4/usr/lib/python3/dist-packages/trac/util/__init__.pyget_reporter_id-s     rcCsL|pd}|dur$t|tr|d}|r|d7}|dtjj|dd7}|S)z7Generate a properly escaped Content-Disposition header.Nutf-8z; z filename=)safe) isinstancestrencodeurllibparsequote)typefilenamerrrcontent_dispositionEs  r#nt)getusercCs*z ttdWStyYdSw)z*Retrieve the identity of the process ownerrunknown)pwdgetpwuidosgeteuidKeyErrorrrrrr%Ws  r%c@seZdZdZdS) WindowsErrorz?Dummy exception replacing WindowsError on non-Windows platformsN)__name__ __module__ __qualname____doc__rrrrr,asr,cCs|ritjdkr1t|dkr|ddksd|vr/|dd}|ddkr/d|d|dd}|Stjd kri|ddkrct|dksNt|dkr[|ddkr[|dd|dd}nd |dd}|dd}|S) aConverts a Windows-style or POSIX-style path to the native style. i.e. on Windows, convert POSIX path to Windows path, and in a POSIX system, convert Windows path to POSIX path. :param path: the input path :return: the path converted to native style posix:\/rNr$zC:\)r)r lenreplacepathrrr native_pathds     $ r;[rcCst|dkS)NCc) unicodedatacategory)crrrsrAi]cCsdt|ts t|d}td|}td|}|ds!td|r'| dd}t |}t |}|S)NrNFC r4z [A-Za-z]:\\r5) rrr> normalize_control_codes_resub startswithrematchr8 posixpathbasenamer)filepathr"rrrnormalize_filenames      rNFcCdSNFrsrcdstrrrrAcCrOrPrrQrrrrArTr2cCsNt|ts t|t}t|tst|t}t||rdSt||ttBS)NT)rrsysgetfilesystemencoding_rename_atomic MoveFileExMOVEFILE_REPLACE_EXISTINGMOVEFILE_WRITE_THROUGHrQrrr_renames   r\TcCsTtddddddd}|dkrdSzt||ddttB|ot|Wt|St|w)Nri'z Trac renameF)CreateTransactionMoveFileTransactedrZr[CommitTransaction CloseHandle)rRrStarrrrXs rXc Cst||rdSz t||WdStyX}z<|jtjkrd|tddf}t||t||zt|Wn t yEYnwWYd}~dSWYd}~dSd}~ww)Nz%s-%08xrl) r\r)renameOSErrorerrnoEEXISTrandomrandintunlink Exception)rRrSeoldrrrrcs&     rcc@sZeZdZdZ  dddZdd Zd d Zd d ZeZeZ ddZ ddZ e ddZ dS) AtomicFileaDA file that appears atomically with its full content. This file-like object writes to a temporary file in the same directory as the final file. If the file is committed, the temporary file is renamed atomically (on Unix, at least) to its final name. If it is rolled back, the temporary file is removed. wr]rstrictc Csd|_tj||_tj|j\}}tj|d|d\}|_d|vr%in||d} tj |||fi| |_z9t |j} t tdrJt |j| j t tdr\t | dr\t|j| jt tdrmt|jd | jWdSWdStyyYdSw) N-)prefixdirbencodingerrorschmodchflagsst_flagschownr])_filer)r:realpath_pathsplittempfilemkstemp_tempfdopenstathasattrrwst_moderxryrzst_gidrd) selfr:modebufsizerurvrrr fdkwargsstrrr__init__s(     zAtomicFile.__init__cCs t|j|SN)getattrr{)rr rrr __getattr__ zAtomicFile.__getattr__cCsV|jdurdSz|jd}|_|t|j|jWdSty*t|jwr)r{closercrr}rjr)rirfrrrcommits   zAtomicFile.commitcCst|jdurdSz |jd}|_|Wz t|jWdSty'YdSwzt|jWwty9Ywwr)r{rr)rirrjrrrrrollbacks    zAtomicFile.rollbackcCs|Srrrrrr __enter__szAtomicFile.__enter__cCs |dSr)r)rexc_type exc_value tracebackrrr__exit__rzAtomicFile.__exit__cCs|jdup|jjSr)r{closedrrrrrAszAtomicFile.N)rnr]rro)r-r.r/r0rrrrr__del__rrpropertyrrrrrrms   rmrrrocCsTd|vrin||d}t||fi| }|WdS1s#wYdS)z#Read a file and return its content.rsrtN)openread)r:rrurvrrrrr read_files$rrncCsd|vrin||d}t||fi|-}|r1t|ttfr$||n||WddSWddSWddS1sDwYdS)zVCreate a new file with the given data. :data: string or iterable of strings. rsrtN)rrrbyteswrite writelines)r:datarrurvrrrrr create_file!s  "rc Cstj|}tjtjtj}ttdr|tj7}d} z|tt ||ddfWSt y\}z&|j t j kr9|d7}|dkrGt d|d|d||df}WYd }~nd }~wwq) z7Create a new file. An index is added if the path existsO_BINARYr2iwbdzFailed to create unique name: z%s.%d%srN)r)r:splitextO_CREATO_WRONLYO_EXCLrrrrrdrerfrj)r:partsflagsidxrkrrrcreate_unique_file/s$     "rcCs\t|d}t|}|j}||d||WddS1s'wYdS)OUpdate modified time of the given file. The file is created if missing.abr2N)rr)fstatfilenost_sizetruncate)r"rrsizerrr touch_fileDs  "rc Cstz t|dWdSty9}z$|jtjkr-t|dWdn1s'wYnWYd}~dSd}~ww)rNr)r)utimerdreENOENTr)r"rkrrrrQs  c Cs|zt|jj|\}}|t|jj|Wnty4}z|jdt |WYd}~dSd}~ww|j d|dS)Nz/Couldn't save backup of configuration file (%s)z(Saved backup of configuration file in %s) rconfigr"rshutilcopyfileIOErrorlogwarningrinfo)envsuffixbackuprrkrrrbackup_config_file^src Cst}||_|dur)t|t}|dd|_|jt ddddt |7_|rG|j ds8|jd7_tj |_ d|_|jd O_ntj|_ d |_|rW|jd O_|rdtj |_ |jd O_|rst|trp|d n||_|S)aXCreate a instance of `ZipInfo`. :param filename: file name of the entry :param mtime: modified time of the entry :param dir: if `True`, the entry is a directory :param executable: if `True`, the entry is a executable file :param symlink: if `True`, the entry is a symbolic link :param comment: comment of the entry Nz     rcCst|A}|D]3}|drq |d}||}tjj|g|R}tj |}tj |s7t |t ||dq WddS1sIwYdS)Nr5r) rZipFilenamelistrr~rr)r:joindirnameisdirmakedirsr)srcfiledestdirzipentrynamescontentr"rrrrextract_zipfiles        "rc@seZdZdZdddZdS) NaivePopenaThis is a deadlock-safe version of popen that returns an object with errorlevel, out (a string) and err (a string). The optional `input`, which must be a `str` object, is first written to a temporary file from which the process will read. (`capturestderr` may not work under Windows 9x.) Example:: print(Popen3('grep spam','\n\nhere spam\n\n').out) Nc CsTt}d||f}|dur2t}t|d }||Wdn1s'wY|d|}|r>t}|d|}zCd|_t|d?|_t||_ |rVt||_Wtj |rbt ||rotj |rot ||r~tj |rt |dSdSdStj |rt ||rtj |rt ||rtj |rt |www)Nz ( %s ) > %srz rU) rmktemprrerrr)system errorlevelroutr:isfileremove)rcommandinput capturestderroutfileinfiletmperrfilerrrrs@             zNaivePopen.__init__NN)r-r.r/r0rrrrrrs rcsBt|tr|n|jfdd}fdd}tjdkr|S|S)aTerminate the process. If the process has already finished and has not been waited for, the function does not raise OSError and WindowsError exceptions unlike a terminate method of `subprocess.Popen`. :param process: the integer id (`pid`) of the process. cs@ddl}d}|jj|d}|jj|d|jj|dS)Nrr2Fr])ctypeswindllkernel32 OpenProcessTerminateProcessra)rPROCESS_TERMINATEhandlepidrr terminate_wins z terminate..terminate_winc sRddl}z t|jWdSty(}z|jtjkrWYd}~dSd}~ww)Nr)signalr)killSIGTERMrdreESRCH)rrkrrr terminate_nixs z terminate..terminate_nixwin32)rintrrVplatform)processrrrrr terminates    r cCs"|r tj|r dSt|dS)zCreate as many directories as necessary to make `path` exist. If `overwrite` is `True`, don't raise an exception in case `path` already exists. N)r)r:existsr)r: overwriterrrrsrcsPddfddfddDfdd||d S) zRecursively copy a directory tree using copy2() (from shutil.copytree.) Added a `skip` parameter consisting of absolute paths which we don't want to copy. cSs"t|tr|tp t}|Sr)rrrrVrWrr9rrrstr_path s  zcopytree..str_pathcs&rtj|rt|dSdSdSr)r)r:rrir9rrrremove_if_overwritingsz'copytree..remove_if_overwritingcsg|]}|qSrr).0r)rrr zcopytree..c st|}t|dg}|D]}}tj||}|vrqtj||}z0r=tj|r=|t|}t||ntj|rI||n |t ||Wqt t fyr}z| ||t|fWYd}~qd}~wt jy} z|| jdWYd} ~ qd} ~ wwzt ||Wn$tyYnt y}z| ||t|fWYd}~nd}~ww|rt |dS)Nrr)r)listdirrr:rislinkreadlinkrrrcopy2rrdappendrErrorextendrcopystatr,) rRrSrrvr srcnamedstnamelinktowhyr) copytree_recrrskipsymlinksrrr"sH          zcopytree..copytree_recNr)rRrSr$r#rr)r"rrr#rr$rcopytrees  "r%cCs0dd}||}||}||kp||tjS)z]Return True iff `path` is equal to parent or is located below `parent` at any level. cSstjtj|Sr)r)r:normcaseabspathr9rrrrE>sz is_path_below..normalize)rHr)sep)r:parentrErrr is_path_below:sr*c@s2eZdZdZdZ  d ddZd d Zd d ZdS) file_or_stdaContext manager for opening a file or using a standard stream If `filename` is non-empty, open the file and close it when exiting the block. Otherwise, use `sys.stdin` if opening for reading, or `sys.stdout` if opening for writing or appending.Nrr]rrocCs"||_||_||_||_||_dSr)r"rrrurv)rr"rrrurvrrrrNs  zfile_or_std.__init__cCsn|jsd|jvr tjntj}d|jvr|j}|Sd|jvrin|j|jd}t|j|j|j fi||_ |j S)Nrrsrt) r"rrVstdinstdoutbufferrurvrrfile)rrrrrrrVs  zfile_or_std.__enter__cCs|jdur |jdSdSr)r/r)retevtbrrrras zfile_or_std.__exit__)rr]rro)r-r.r/r0r/rrrrrrrr+Es  r+cCs.t|}|j|j}}|dkr|Sd||fS)z6Return the fully qualified class name of given object. __builtin__z%s.%s)r!r.r-)objr@mnrrr fq_class_namehsr7cCs|jjtt|ddS)z`Return the number of arguments expected by the given function, unbound or bound method. __self__F)__code__ co_argcountboolr)rrrrarityosr<cCs$ddl}t}|j|d|S)z.Retrieve the last traceback as a `str` string.rN)r/)rioStringIO print_excgetvalue)rr2rrrget_last_tracebackvs rAzbuild/bdist\.[^/]+/egg/(.*)c shg}t|}|r=tjD]0}z%t|d}||d} WdWn1s-wYWq t y<Yq w|sNddl }| || ||}d|kr[t |ks^dSdStd||} |d|} dtd} |ddD]} | | }|r|dnqxfdd || |D} t||d }fd d ||d| D}| ||fS) zReturn `content` number of lines before and after the specified `lineno` from the (source code) file identified by `filename`. Returns a `(lines_before, line, lines_after)` tuple. rr2Nr)rNrzcoding[=:]\s*([-\w.]+)r6cg|] }t|dqS r rstriprlcharsetrrrz'get_lines_from_file..rDcrBrCrErGrIrrrrK) _egg_path_rerJrVr:rrrgroup splitlinesrj linecache checkcachegetlinesr7maxrIcompilesearchr rF)r"linenocontextglobalslinesrJr:rrOlbounduboundreplinestrbeforelineafterrrIrget_lines_from_filesL  &           r`c Csg}|rP|jjd}|dvr|dd=|dd}|sK|jjj}|dd}|jd}t||d|jj\}}}| |||||||jjj |jjd |j }|s|S) z)Return frame information for a traceback.__traceback_hide__)r]before_and_thisNrr4r5r2r)rr"rUr^ lines_before lines_afterfunctionvars) tb_framef_localsrf_code co_filenamer8 tb_linenor` f_globalsrco_nametb_next)r2framestb_hider"rUr]r^r_rrrget_frame_infos,      rqc CsTtj}zt|WSty)}ztjD] }||vr"tj|=q|d}~ww)z Safe imports: rollback after a failed import. Initially inspired from the RollbackImporter in PyUnit, but it's now much simpler and works better for our needs. See http://pyunit.sourceforge.net/notes/reloading.html N)rVmodulescopy importlib import_modulerj) module_namealready_importedrkmodnamerrrsafe__import__s  ryc CsNztt|WSty&}zdt|t|t|fWYd}~Sd}~ww)z`repr` replacement which "never" breaks. Make sure we always get a representation of the input `x` without risking to trigger an exception (e.g. from a buggy `x.__repr__`). .. versionadded :: 1.0 z&<%s object at 0x%X (repr() error: %s)>N)r reprrjr7idr)xrkrrr safe_reprs r}cCsN|j}|sdSt|dd}|ddd}t|dkr!|dnd}||fS)zReturn the docstring of an object as a tuple `(summary, description)`, where `summary` is the first paragraph and `description` is the remaining text. rz r2rrDrDN)r0r r~r8r7)r4docsummary descriptionrrrget_docsr)__file__r- __package__cCs4t|}|dd|jD|dddS)zImport the namespace of a module into a globals dict. This function is used in stub modules to import all symbols defined in another module into the global namespace of the stub, usually for backward compatibility. css |] }|dtvr|VqdSrN) _dont_importritemrrr s  z#import_namespace..import_namespaceN)rtruupdate__dict__itemspop) globals_dictrvmodulerrrrs rcCs|j}|j}|dr|dd}tj|dkrtj|}tj|d}|tj d|rRtj|}d | ddd}|sH |S|tj d|s1|S)z6Return the base path the given module is imported from)z.pycz.pyoNr] __init__.pyr.) rr-rr)r:rLrrr8r(rr~)rr:rv base_pathrrrget_module_paths    rc si}tj|ddD]Zdsq dddDdr3|fdddDq d rctd }t |}|fd d|DWd n1s]wYq q |S) zgReturn a dictionary mapping Python module source paths to the distributions that contain them. Tonly top_level.txtcSsg|]}|dqS)r5rrtoprrrr rzget_sources.. SOURCES.txtc3s.|]tfddDrfVqdS)c3s|]}|VqdSrrHrrRrrr$s(get_sources...Nanyrdist toplevelsrrr"s zget_sources..RECORDc3s2|]tfddDrdfVqdS)c3s|] }d|VqdSrrrrowrrr*srrNrrrrrr)s N) pkg_resourcesfind_distributions has_metadataget_metadata_linesrr=r> get_metadatacsvreader)r:sourcesrrrrr get_sourcess*      rc sddlddlddl}ddlm}fddt||jr^fdd}|}t|}|j dd }t j |j d vr@|d 7}n|d 7}tj|d dD]}t j |sY||||r[nqKiSd}i}dd} |drmdnd} z|| fdd|DD] } | || | <q~W|Sty} z|d| |t| d} |D]} | || | <qWYd} ~ |Sd} ~ wjjy} z|d| |t| d} |D]} | || | <qWYd} ~ |Sd} ~ ww)aaGet a dictionary containing package information for a package `dist` can be either a Distribution instance or, as a shortcut, directly the module instance, if one can safely infer a Distribution instance from it. Always returns a dictionary but it will be empty if no Distribution instance can be created for the given module. rN)_cs||Sr)message_from_stringr)rr )r rr parse_pkginfo?z"get_pkginfo..parse_pkginfoc s~|jdr |S|dr&tjdtfdd|dDS|dr?tjtfdd|dDS|drlt | d}t |}tfd d|DWdS1sgwY|d rz&|d }|d d |jd tfddttDrWdSWn tjjfyYnwdd}|dr||dvS|j|kS)Nz.eggzinstalled-files.txtz../c3 |] }tj|kVqdSrr)r:normpathrr  resource_namerrrHz4get_pkginfo..has_resource..rc3rrrrrrrrMrrc3s|] }|dkVqdSrr)rrrrrrRPKG-INFOProvidesrrc3s*|]}dd|dvVqdS)rNr2)r)rr6)rprovidesrrrXs"Tr5rr)locationr has_resourcerr)r:rrrr=r>rrrget_allr-r~ranger7rErrors MessageErrorkeylower)rrrrrpkginfotoplevel)r r)rrrrrCsD               z!get_pkginfo..has_resourcerr5)rz __init__.pycz __init__.pyoz /__init__.pyz.pyTr) authorz author-email maintainerzmaintainer-emaillicensez home-pagerr rversioncSs|ddS)Nrpr)rr8)attrrrrrEtrzget_pkginfo..normalizeMETADATArcsg|]}|vr|qSrrrr)rrrryszget_pkginfo..z6Failed to read %(metadata)s file for %(dist)s: %(err)s)metadatarrz7Failed to parse %(metadata)s file for %(dist)s: %(err)s)r email.errorstypestrac.util.translationrr ModuleTyperr-r8r)r:rLrrrrrrr rvr)rrrrr module_pathrattrsrrErrrkrr)r rrr get_pkginfo0sb             rcCsi}dD]*}t||d}|r.t|tr.|dvr&d}|dddd}nt|}|||<qt|ddp:t|dd}|d krO|ddd d |d<|Sd|d<|S) z2Get a dictionary containing metadata for a module.) r author_emailrmaintainer_email home_pageurlrrtracr)rrr$zURL: rrevisionz$Rev$zRev: r)rrrr8stripr )rrkvrrrrget_module_metadatas&   rrcCsg}tdttd}t||j|kr6| t t d| |t||j|ksd|}t||krG|d|S|S)Nz{}{}r)hashlibsha1formatr)getpidrrr7 digest_sizerr_entropyrgrdigestr)r6resulthasherrrrurandoms r cCs<dddt|ddD}t||kr|d|S|S)z2Generate `digits` number of hex digits of entropy.rcss|]}d|VqdS)z%.2xNr)rrrrrrszhex_entropy..r2r6N)rrr7)digitsrrrr hex_entropys rr6cCsdddt|DS)z8Returns a string of `length` random letters and numbers.rcss&|]}ttjtjdVqdS)z/.N)rgchoicestring ascii_lettersrrr|rrrrszsalt..)rr)lengthrrrsalts r$1$c s8|}|}tt|}t|}t||}t||tfddttDfdd}|t||tdD]:}t}|d@r\|n||drj|||drs||d@r}|n||qLfd d } ||d tt| d S) zBased on FreeBSD src/lib/libcrypt/crypt.c 1.2 :param password: the plain text password to crypt :param salt: the raw salt :param magic: our magic string c3s|] }|dVqdS)rNr)ri)mixinrrrrzmd5crypt..c3s<t}|r|d@rdVndV|dL}|sdSdS)Nr2r)r7)r)passwordrriter_password_or_zeros  z'md5crypt..iter_password_or_zeroir2c3sd}dD]'\}}}|d>|d>B|B}tdD] }||d@V|dL}qqd}td D] }||d@V|dL}q5dS) Ns@./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz))rr )r2r )r6rU)r ) rrrUr?r r6)r)valueitoa64arsr@rr)finalrr iter_ito64s     zmd5crypt..iter_ito64rascii) r rmd5rrrrr7r) rrmagic magic_argsalt_argr5rrm2r r)r rrrmd5crypts4$          rc@s^eZdZdZdZdddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ dS)RangesuHolds information about ranges parsed from a string :author: Tim Hatch >>> x = Ranges("1,2,9-15") >>> 1 in x True >>> 5 in x False >>> 10 in x True >>> 16 in x False >>> [i for i in range(20) if i in x] [1, 2, 9, 10, 11, 12, 13, 14, 15] Also supports iteration, which makes that last example a bit simpler: >>> list(x) [1, 2, 9, 10, 11, 12, 13, 14, 15] Note that it automatically reduces the list and short-circuits when the desired ranges are a relatively small portion of the entire set: >>> x = Ranges("99") >>> 1 in x # really fast False >>> x = Ranges("1, 2, 1-2, 2") # reduces this to 1-2 >>> x.pairs [(1, 2)] >>> x = Ranges("1-9,2-4") # handle ranges that completely overlap >>> list(x) [1, 2, 3, 4, 5, 6, 7, 8, 9] The members 'a' and 'b' refer to the min and max value of the range, and are None if the range is empty: >>> x.a 1 >>> x.b 9 >>> e = Ranges() >>> e.a, e.b (None, None) Empty ranges are ok, and ranges can be constructed in pieces, if you so choose: >>> x = Ranges() >>> x.appendrange("1, 2, 3") >>> x.appendrange("5-9") >>> x.appendrange("2-3") # reduce'd away >>> list(x) [1, 2, 3, 5, 6, 7, 8, 9] Reversed ranges are ignored, unless the Ranges has the `reorder` property set. >>> str(Ranges("20-10")) '' >>> str(Ranges("20-10", reorder=True)) '10-20' As rendered ranges are often using ',​' (comma + Zero-width space) to enable wrapping, we also support reading such ranges, as they can be copy/pasted back. >>> str(Ranges('1,​3,​5,​6,​7,​9')) '1,3,5-7,9' u4[0-9]+(?:[-:][0-9]+)?(?:,​?[0-9]+(?:[-:][0-9]+)?)*NFcCs&g|_d|_|_||_||dSr)pairsrrsreorder appendrange)rrrrrrrds zRanges.__init__c Cs|sdS|j}t|trtd|}|D]8}z tt|dd\}}Wnty5t|t|}}Ynw||krB|||fq|j rL|||fq| dS)zAdd ranges to the current one. A range is specified as a string of the form "low-high", and `r` can be a list of such strings, a string containing comma-separated ranges, or `None`. Nu,​?rpr2) rrrrIr~mapr  ValueErrorrr_reduce)rrpr|rrsrrrrjs"    zRanges.appendrangecCs|j}|d}|dt|krJ||ddd||dkr>||dt||d||ddf||<||d=n|d7}|dt|ks|r\|dd|_|dd|_dSd|_|_dS)z5Come up with the minimal representation of the rangesrr2r]N)rsortr7rRrrs)rrrrrrrs . zRanges._reduceccs0|jD]\}}t||dD]}|VqqdS)z This is another way I came up with to do it. Is it faster? from itertools import chain return chain(*[range(a, b+1) for a, b in self.pairs]) r2N)rr)rrrsrrrr__iter__s zRanges.__iter__cCsd|jdur0|j|kr|jkr0ndS|jD]\}}||kr'|kr(dS||kr/dSqdS)z2 >>> 55 in Ranges() False NTF)rrsr)rr|rrsrrr __contains__s$zRanges.__contains__cCsHg}|jD]\}}||kr|t|q|d||fqd|S)zProvide a compact string representation of the range. >>> (str(Ranges("1,2,3,5")), str(Ranges()), str(Ranges('2'))) ('1-3,5', '', '2') >>> str(Ranges('99-1')) # only nondecreasing ranges allowed '' %d-%d,)rrrr)rrrrsrrr__str__s  zRanges.__str__cCs0|jdus |jdur dSt|j|jdtjS)zThe length of the entire span, ignoring holes. >>> (len(Ranges('99')), len(Ranges('1-2')), len(Ranges(''))) (1, 2, 0) Nrr2)rrsminrVmaxsizerrrr__len__szRanges.__len__cCs|jduo |jduS)zyReturn True iff the range is not empty. >>> (bool(Ranges()), bool(Ranges('1-2'))) (False, True) N)rrsrrrr __nonzero__szRanges.__nonzero__cCs~t}|j|j|j|_|_|_g|_|jD]%\}}||kr:||kr1|j||f||_|S|j||fq|S|S)aTruncate the Ranges by setting a maximal allowed value. Note that this `max` can be a value in a gap, so the only guarantee is that `self.b` will be lesser than or equal to `max`. >>> r = Ranges("10-20,25-45") >>> str(r.truncate(30)) '10-20,25-30' >>> str(r.truncate(22)) '10-20' >>> str(r.truncate(10)) '10' )rrrsrrr)rrRrrrsrrrrszRanges.truncaterP)r-r.r/r0RE_STRrrrrrrr"r#rrrrrrsH   rcstgdfdd}t|D]}dur|q|dkr&|q||qdur5|dS)zConverts a list of revisions to a minimal set of ranges. >>> to_ranges([2, 12, 3, 6, 9, 1, 5, 11]) '1-3,5-6,9,11-12' >>> to_ranges([]) '' Ncs0kr tdSdfdS)Nr)rrrbeginendrangesrrstoreszto_ranges..storer2r)sortedr)revsr)revrr%r to_rangess     r-c@s0eZdZdZddZddZddZdd Zd S) lazyz3A lazily-evaluated attribute. :since: 1.0 cCs||_t||dSr)fn functoolsupdate_wrapper)rr/rrrrsz lazy.__init__cCsD|dur|S|jj|jvr|j|jjS||}||j|jj<|Srr/r-r)rinstanceownerrrrr__get__s z lazy.__get__cCs||j|jj<dSr)rr/r-)rr3rrrr__set__sz lazy.__set__cCs"|jj|jvr|j|jj=dSdSrr2)rr3rrr __delete__ szlazy.__delete__N)r-r.r/r0rr5r6r7rrrrr. s  r.z(\d+)cCs,t|}tt|ddd|ddd<|S)zzComparison function for natural order sorting based on http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/214202.r2Nr6)DIGITSr~rr )spiecesrrrembedded_numbers(s r;cs\i|dur|D]}g|<q|D] \}}|g|q|dur%Sfdd|DS)z >>> rv = partition([(1, "a"), (2, "b"), (3, "a")]) >>> rv == {'a': [1, 3], 'b': [2]} True >>> partition([(1, "a"), (2, "b"), (3, "a")], "ab") [[1, 3], [2]] Ncsg|]}|qSrrrrrrr@rzpartition..) setdefaultr)iterableorderrrr?rr<r partition0s  r@c Cs\z||}Wn ttfy|YSw|dur ||kr ||}|dur,||kr,||}|Sr) TypeErrorr) numeric_typer9defaultr rRrrrr _as_numericCs rDcCtt||||S)zConvert s to an int and limit it to the given range, or return default if unsuccessful. :since 1.3.6: the default value of the `default` argument is `None` )rDr r9rCr rRrrras_intOrGcCrE)ztConvert s to a float and limit it to the given range, or return default if unsuccessful. :since: 1.3.6 )rDfloatrFrrras_floatXrHrJc Cs~t|tr,ztt|WSty+|}|dvr YdS|dvr'YdS|YSwzt|WSttfy>|YSw)aSConvert the given value to a `bool`. If `value` is a string, return `True` for any of "yes", "true", "enabled", "on" or non-zero numbers, ignoring case. For non-string arguments, return the argument converted to a `bool`, or `default` if the conversion fails. :since 1.2: the `default` argument can be specified. )yestrueenabledonT)nofalsedisabledoffF)rrr;rIrrrrA)rrCrrras_boolas    rScGsdtddd|DS)z=Strip `/` from the arguments and join them with a single `/`.r5Ncss|] }|r|dVqdS)r5Nr)reachrrrr~szpathjoin..)rfilter)rrrrpathjoin|srWrcCs,|sgSddt||D}dd|DS)aSplit a string at `sep` and return a list without any empty items. >>> to_list('1,2, 3,4 ') ['1', '2', '3', '4'] >>> to_list('1;2; 3;4 ', sep=';') ['1', '2', '3', '4'] >>> to_list('1,2;3 4 ', sep=r'[,;\s]+') ['1', '2', '3', '4'] >>> to_list('') [] >>> to_list(None) [] >>> to_list([]) [] :since 1.3.6: the `sep` argument may be a regular expression cSsg|]}|qSrrTrrrrrrzto_list..cSsg|]}|r|qSrrrrrrrr)rIr~) splittabler(r~rrrto_listsrYcCs0z||}Wn tyYdSw|||<dS)z`Substitute an item if the item is found in a list, otherwise leave the list unmodified. N)indexr)the_listitem_to_remove item_to_addrZrrrsub_vals   r^zcompat presentation translationrr)rrro)rrnrro)NFFFN)Fr)r)r6)r)NNN)r)wrrer0rrtr=r)rrKrgrIrrVrrr urllib.parserr>rtrac.util.datefmtrrrrtrac.util.textrrrr r rr#r getpassr%r'r, NameErrorrdr;rSrrVrchrrrFrNcan_rename_open_filer\rXrrZr[rr MoveFileExWrYktmw32r^r`MoveFileTransactedWr_rarjrcobjectrmrrrrrrrrr rr%r*r+r7r<rArLr`rqryr}r frozensetrrrrrrrNotImplementedErrorRandomrrrrrr-r.r8r;r@rDrGrJrSrWrYr^ __no_apidoc__rrrrs               E       7' # 6 #  / X      PV