L iMddlZddlZddlZddlmZddlmZmZddlZddlm Z ejZ ddddZ Gdd ejZd Zdd ZGd d eZGddej&ZGddej*ZGddeZefdZefdZedk(rj@yy)Nwraps)MappingCallable) PercentStylez%(levelname)s: %(message)sz %(message)s)*INFODEBUGc.eZdZdZdfd ZfdZxZS)LevelFormatteraLog formatter with level-specific formatting. Formatter class which optionally takes a dict of logging levels to format strings, allowing to customise the log records appearance for specific levels. Attributes: fmt: A dictionary mapping logging levels to format strings. The ``*`` key identifies the default format string. datefmt: As per py:class:`logging.Formatter` style: As per py:class:`logging.Formatter` >>> import sys >>> handler = logging.StreamHandler(sys.stdout) >>> formatter = LevelFormatter( ... fmt={ ... '*': '[%(levelname)s] %(message)s', ... 'DEBUG': '%(name)s [%(levelname)s] %(message)s', ... 'INFO': '%(message)s', ... }) >>> handler.setFormatter(formatter) >>> log = logging.getLogger('test') >>> log.setLevel(logging.DEBUG) >>> log.addHandler(handler) >>> log.debug('this uses a custom format string') test [DEBUG] this uses a custom format string >>> log.info('this also uses a custom format string') this also uses a custom format string >>> log.warning("this one uses the default format string") [WARNING] this one uses the default format string c|dk7r td|t}t|tr|}i}nsetLeveljoinkeys)kwargsr4r6modehr5r9fsdfsr!rr<fr"rJs r$ configLoggerrQYs Zzz*d+H v *"6M  v v!55 ::j$/zz*c* ##Hd3AZZ$/F%%f-A3 ZZ+ .F Z,""6*- Hd #B **Y %C JJw $E S% (CjjB'G  ;;  NN3 yy  A ! {{f!::k59 JJw %E  yy'7$>??r%ctj}t|jjj }|dk(r|g|z}nj||vry||vra|g}|j |dz}|dz}t|}t|}||kr*||d||k(r|j|||dz }||kr*D]}|dk(rq|jtj|jddD]} |j| |jddD]} |j| d|_y|jj|} tj | _g| _ g| _ d| _d| _y)zReset the logger named 'parent' and all its children to their initial state, if they already exist in the current configuration. r=N.FT)rr=sortedmanager loggerDictrJindexlenappendrHWARNINGr4 removeHandlerr< removeFiltersdisabledNOTSETr"r>) r;r=existingloggers_to_resetiprefixedpflen num_existingrCrMrPr9s r$rBrBs~ < MM'// *]]1% &""1% &\\!_ &""1% &!DM\\,,T2F">>FL FOFN#F #FO$r%ceZdZUdZeej Zege fe d<dZ dZ ddZ ddZdZd Zd Zd Zd Zdd ZdZdZdZy)TimeraYKeeps track of overall time and split/lap times. >>> import time >>> timer = Timer() >>> time.sleep(0.01) >>> print("First lap:", timer.split()) First lap: ... >>> time.sleep(0.02) >>> print("Second lap:", timer.split()) Second lap: ... >>> print("Overall time:", timer.time()) Overall time: ... Can be used as a context manager inside with-statements. >>> with Timer() as t: ... time.sleep(0.01) >>> print("%0.3f seconds" % t.elapsed) 0... seconds If initialised with a logger, it can log the elapsed time automatically upon exiting the with-statement. >>> import logging >>> log = logging.getLogger("my-fancy-timer-logger") >>> configLogger(logger=log, level="DEBUG", format="%(message)s", stream=sys.stdout) >>> with Timer(log, 'do something'): ... time.sleep(0.01) Took ... to do something The same Timer instance, holding a reference to a logger, can be reused in multiple with-statements, optionally with different messages or levels. >>> timer = Timer(log) >>> with timer(): ... time.sleep(0.01) elapsed time: ...s >>> with timer('redo it', level=logging.INFO): ... time.sleep(0.02) Took ... to redo it It can also be used as a function decorator to log the time elapsed to run the decorated function. >>> @timer() ... def test1(): ... time.sleep(0.01) >>> @timer('run test 2', level=logging.INFO) ... def test2(): ... time.sleep(0.02) >>> test1() Took ... to run 'test1' >>> test2() Took ... to run test 2 _timezelapsed time: %(time).3fszTook %(time).3fs to %(msg)sNc|j||.dD])}tj|td|z||_||nt |_||_y)N)msgr"z*'%s' can't be specified without a 'logger')resetlocalsr(rr9 TIME_LEVELr"rj)rr9rjr"startargs r$rzTimer.__init__#se 5 >' Y8<<$0$%QTW%WXX Y #/UZ r%cr||j|_n||_|j|_d|_y)z0Reset timer to 'start_time' or the current time.N)rhrnlastelapsed)rrns r$rkz Timer.reset-s- =DJDJJJ  r%c<|j|jz S)z=Return the overall time (in seconds) since the timer started.)rhrnrs r$timez Timer.time6szz|djj((r%cp|j}||jz |_||_|jS)z=Split and return the lap time (in seconds) in between splits.rhrrrs)rcurrents r$splitz Timer.split:s.**,*  ||r%c|s |j}|jddkr|j||dz}|S |d|iz}|S#ttf$rY|SwxYw)zFormat 'time' value in 'msg' and return formatted string. If 'msg' contains a '%(time)' format string, try to use that. Otherwise, use the predefined 'default_format'. If 'msg' is empty or None, fall back to 'default_msg'. z%(time)rrjrvrv) default_msgfindrKeyErrorr)rrjrvs r$ formatTimezTimer.formatTimeAsw ""C 88I  "%%T(BBC   VTN* j)   sAAAc>|j|_d|_|S)zStart a new laprqrxrus r$ __enter__zTimer.__enter__RsJJL   r%c|j}|j|ry|j|j|}|j|d}|jj |j ||y)zEnd the current lap. If timer has a logger, log the time elapsed, using the format string in self.msg (or the default one). Nr|)rzr9rrjlogr")rexc_type exc_value tracebackrvmessage msg_partss r$__exit__zTimer.__exit__Xs\zz| ;; ( //$((D1!HHd3   GY7r%c 2t|tr8|jsdjz_t fd}|S|xs|j d}|j dj }jj||S)aVIf the first argument is a function, return a decorator which runs the wrapped function inside Timer's context manager. Otherwise, treat the first argument as a 'msg' string and return an updated Timer instance, referencing the same logger. A 'level' keyword can also be passed to override self.level. zrun '%s'cD5|i|cdddS#1swYyxYwr')argskwdsfuncrs r$wrapperzTimer.__call__..wrapperts(/..///srjr") rrrjr-rr(r"r#r9)r func_or_msgrKrrjr"rs` @r$__call__zTimer.__call__gs k8 ,D88% 5 4[ / /N2E!2CJJw 3E>>$++sE: :r%c|jSr'rsrus r$ __float__zTimer.__float__s ||r%c,t|jSr')intrsrus r$__int__z Timer.__int__s4<<  r%c d|jzS)Nz%.3frrus r$__str__z Timer.__str__s $$r%)NNNNr')r-r.r/r0 staticmethodtimeit default_timerrhrfloat__annotations__r}rrrkrvrzrrrrrrrrr%r$rgrgsi6r".f.B.B!CE8BI C-K2N)" 8;0!%r%rgceZdZdZdZdZy)ChannelsFilteraQProvides a hierarchical filter for log entries based on channel names. Filters out records emitted from a list of enabled channel names, including their children. It works the same as the ``logging.Filter`` class, but allows the user to specify multiple channel names. >>> import sys >>> handler = logging.StreamHandler(sys.stdout) >>> handler.setFormatter(logging.Formatter("%(message)s")) >>> filter = ChannelsFilter("A.B", "C.D") >>> handler.addFilter(filter) >>> root = logging.getLogger() >>> root.addHandler(handler) >>> root.setLevel(level=logging.DEBUG) >>> logging.getLogger('A.B').debug('this record passes through') this record passes through >>> logging.getLogger('A.B.C').debug('records from children also pass') records from children also pass >>> logging.getLogger('C.D').debug('this one as well') this one as well >>> logging.getLogger('A.B.').debug('also this one') also this one >>> logging.getLogger('A.F').debug('but this one does not!') >>> logging.getLogger('C.DE').debug('neither this one!') cz||_t||_|Dcic]}|t|c}|_ycc}wr')namesrYnumlengths)rrns r$rzChannelsFilter.__init__s1 u:+01a3q6 1 1s8c|jdk(ry|jD]W}|j|}||jk(ry|jj |d|dk(sD|j|dk(sWyy)NrTrTF)rrrrCr~)rr,rCnlens r$filterzChannelsFilter.filterss 88q=JJ D<<%Dv{{"!!$40A5&++d:Ks:R   r%N)r-r.r/r0rrrr%r$rrs42 r%rc8eZdZfdZdZdZdZddZxZS)CapturingLogHandlerctt| |g|_t |t rt j||_y||_y)N)r") rrrrecordsrrrrAr9)rr9r"r#s r$rzCapturingLogHandler.__init__s@ !411> fc "!++F3DK DKr%cl|jj|_|jj|_|jj |_|jj||jj|jd|j_d|j_|S)NF) r9r^original_disabledr"original_levelr>original_propagaterGrHrus r$rzCapturingLogHandler.__enter__s}!%!5!5"kk//"&++"7"7 t$ TZZ($  %  r%c|jj||jj|j|j|j_|j |j_|Sr')r9r\rHrrr^rr>)rtypevaluers r$rzCapturingLogHandler.__exit__sU !!$' T001#55  $ 7 7  r%c:|jj|yr')rrZ)rr,s r$emitzCapturingLogHandler.emits F#r%cddl}|j|}|jD]#}|j|j s#y|d|z}J|)NrTz(Pattern '%s' not found in logger records)recompilersearch getMessage)rregexprjrpatternrs r$ assertRegexzCapturingLogHandler.assertRegexsU**V$ A~~alln-  ;.``. For example: >>> class BaseClass(object): ... pass >>> class MyClass(LogMixin, BaseClass): ... pass >>> a = MyClass() >>> isinstance(a.log, logging.Logger) True >>> print(a.log.name) fontTools.misc.loggingTools.MyClass >>> class AnotherClass(MyClass): ... pass >>> b = AnotherClass() >>> isinstance(b.log, logging.Logger) True >>> print(b.log.name) fontTools.misc.loggingTools.AnotherClass ct|dsUdj|jj|jjf}t j ||_|jS)N_logrT)hasattrrIr#r.r-rrAr)rrCs r$rz LogMixin.logsOtV$88T^^668O8OPQD))$/DIyyr%N)r-r.r/r0propertyrrr%r$rrs6r%rc>tj|d||dy)z:Raise a warning about deprecated function argument 'name'. is deprecated; category stacklevelN)warningswarn)rCrjrs r$deprecateArgumentrs MMD#6VWXr%cfd}|S)zBDecorator to raise a warning when a deprecated function is called.c4tfd}|S)Ncbtjjdd|i|S)Nrr)rrr-)rrKrrrjs r$rz5deprecateFunction..decorator..wrappers3 MM*.--=!  (( (r%r)rrrrjs` r$ decoratorz$deprecateFunction..decorator s t )  )r%r)rjrrs`` r$deprecateFunctionr s  r%__main__) optionflags)r=)!sysrr functoolsrcollections.abcrrrrr rmr Formatterr rQrBobjectrgFilterrHandlerrr UserWarningrrr-doctestexittestmodELLIPSISfailedrr%r$rs  - ]] &  @:W&&@:F`@F&$Ra%Fa%H)W^^)X)'//)X!v!H+6Y %0$ z CHH_W__)9)9 : A ABr%