B
    ScPC                 @   s  d dl Z d dlZd dlZd dlmZ d dlmZmZ d dlZd dlm	Z	 ej
ZddddZG dd	 d	ejZd
d ZdddZG dd deZG dd dejZG dd dejZG dd deZefddZefddZedkrd dlZe ejejdj  dS )    N)wraps)MappingCallable)PercentStylez%(levelname)s: %(message)sz%(message)s)*INFODEBUGc                   s.   e Zd ZdZd fdd	Z fddZ  ZS )	LevelFormatteray  Log 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
	N%c                s   |dkrt d|d krt}t|tr0|}i }n,t|trPt|}|dd }ntd| tt	| 
|| | j| _i | _x(| D ]\}}t|}|| j|< qW d S )Nr
   z:only '%' percent style is supported in both python 2 and 3r   z&fmt must be a str or a dict of str: %r)
ValueErrorDEFAULT_FORMATS
isinstancestrr   dictpop	TypeErrorsuperr	   __init___fmtdefault_formatcustom_formatsitemsloggingZ_checkLevel)selffmtdatefmtstyler   r   level)	__class__ :lib/python3.7/site-packages/fontTools/misc/loggingTools.pyr   8   s$    


zLevelFormatter.__init__c                sF   | j r6| j |j| j}| j|kr6|| _tr6t|| _tt| 	|S )N)
r   getZlevelnor   r   r   Z_styler   r	   format)r   recordr   )r   r   r    r"   M   s    

zLevelFormatter.format)NNr
   )__name__
__module____qualname____doc__r   r"   __classcell__r   r   )r   r    r	      s    r	   c              K   s  |  dd}|dkr.d| krFd| krFtdnd| ks>d| krFtd|dkr|  dd}|  dd}|rxt||}n|  dd}t|}|g}|  d	d
}|rt|trt|}t|j	d |  dd}|  dd}|  dd}	t
|||	}
|  dg }xP|D ]H}|jdkr ||
 |jsBx|D ]}|| q.W || qW |j	dkrl|  dd|_|  dd}|dk	r|| | rd|  }td| dS )a  A more sophisticated logging system configuation manager.

	This is more or less the same as :py:func:`logging.basicConfig`,
	with some additional options and defaults.

	The default behaviour is to create a ``StreamHandler`` which writes to
	sys.stderr, set a formatter using the ``DEFAULT_FORMATS`` strings, and add
	the handler to the top-level library logger ("fontTools").

	A number of optional keyword arguments may be specified, which can alter
	the default behaviour.

	Args:

		logger: Specifies the logger name or a Logger instance to be
			configured. (Defaults to "fontTools" logger). Unlike ``basicConfig``,
			this function can be called multiple times to reconfigure a logger.
			If the logger or any of its children already exists before the call is
			made, they will be reset before the new configuration is applied.
		filename: Specifies that a ``FileHandler`` be created, using the
			specified filename, rather than a ``StreamHandler``.
		filemode: Specifies the mode to open the file, if filename is
			specified. (If filemode is unspecified, it defaults to ``a``).
		format: Use the specified format string for the handler. This
			argument also accepts a dictionary of format strings keyed by
			level name, to allow customising the records appearance for
			specific levels. The special ``'*'`` key is for 'any other' level.
		datefmt: Use the specified date/time format.
		level: Set the logger level to the specified level.
		stream: Use the specified stream to initialize the StreamHandler. Note
			that this argument is incompatible with ``filename`` - if both
			are present, ``stream`` is ignored.
		handlers: If specified, this should be an iterable of already created
			handlers, which will be added to the logger. Any handler in the
			list which does not have a formatter assigned will be assigned the
			formatter created in this function.
		filters: If specified, this should be an iterable of already created
			filters. If the ``handlers`` do not already have filters assigned,
			these filters will be added to them.
		propagate: All loggers have a ``propagate`` attribute which determines
			whether to continue searching for handlers up the logging hierarchy.
			If not provided, the "propagate" attribute will be set to ``False``.
	handlersNstreamfilenamez8'stream' and 'filename' should not be specified togetherzG'stream' or 'filename' should not be specified together with 'handlers'filemodealoggerZ	fontTools)parentr"   r   r   r
   filtersroot	propagateFr   z, zUnrecognised argument(s): %s)r   r   r   ZFileHandlerZStreamHandlerr   r   	getLogger_resetExistingLoggersnamer	   Z	formatterZsetFormatterr0   Z	addFilter
addHandlerr2   setLeveljoinkeys)kwargsr)   r+   modehr*   r.   ZfsZdfsr   r   r0   fr   r9   r   r   r    configLoggerX   sL    -







r>   r1   c             C   sB  t j}t|jj }| dkr*| g| }nx| |kr6dS | |kr| g}|| d }| d }t|}t|}x6||k r|| d| |kr|||  |d7 }qlW x|D ]}|dkr|	t j
 x |jdd D ]}	||	 qW x |jdd D ]}
||
 qW d|_q|jj| }t j|_g |_g |_d|_d|_qW dS )z Reset the logger named 'parent' and all its children to their initial
	state, if they already exist in the current configuration.
	r1   N   .FT)r   r1   sortedZmanagerZ
loggerDictr9   indexlenappendr7   ZWARNINGr)   removeHandlerr0   ZremoveFiltersdisabledZNOTSETr   r2   )r/   r1   existingZloggers_to_resetiZprefixedZpflenZnum_existingr5   r<   r=   r.   r   r   r    r4      s<    


r4   c               @   s|   e Zd ZdZejZdZdZdddZ	dddZ
d	d
 Zdd Zdd Zdd Zdd ZdddZdd Zdd Zdd ZdS )Timera   Keeps 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
	zelapsed time: %(time).3fszTook %(time).3fs to %(msg)sNc             C   s^   |  | |d kr<x(dD ] }t |d k	rtd| qW || _|d k	rN|nt| _|| _d S )N)msgr   z*'%s' can't be specified without a 'logger')resetlocalsr!   r   r.   
TIME_LEVELr   rJ   )r   r.   rJ   r   startargr   r   r    r     s    

zTimer.__init__c             C   s,   |dkr|   | _n|| _| j| _d| _dS )z2 Reset timer to 'start_time' or the current time. Ng        )_timerN   lastelapsed)r   rN   r   r   r    rK   *  s
    zTimer.resetc             C   s   |   | j S )z? Return the overall time (in seconds) since the timer started. )rP   rN   )r   r   r   r    time3  s    z
Timer.timec             C   s    |   }|| j | _|| _| jS )z? Split and return the lap time (in seconds) in between splits. )rP   rQ   rR   )r   Zcurrentr   r   r    split7  s    zTimer.splitc          	   C   sX   |s
| j }|ddk r*| j||d }n*y|d|i }W n ttfk
rR   Y nX |S )z Format '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)r   )rJ   rS   rS   )default_msgfindr   KeyErrorr   )r   rJ   rS   r   r   r    
formatTime>  s    zTimer.formatTimec             C   s   |   | _d| _| S )z Start a new lap g        )rP   rQ   rR   )r   r   r   r    	__enter__O  s    
zTimer.__enter__c             C   sJ   |   }| jdks|rdS | | j|}| j|d}| j| j|| dS )z End the current lap. If timer has a logger, log the time elapsed,
		using the format string in self.msg (or the default one).
		N)rJ   rS   )rT   r.   rX   rJ   logr   )r   exc_type	exc_value	tracebackrS   messageZ	msg_partsr   r   r    __exit__U  s    zTimer.__exit__c                sj   t |tr:| js d j _t  fdd}|S |pF|d}|dj}j||S dS )a9   If 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.
		zrun '%s'c           	      s     | |S Q R X d S )Nr   )argskwds)funcr   r   r    wrapperq  s    zTimer.__call__.<locals>.wrapperrJ   r   N)	r   r   rJ   r$   r   r!   r   r   r.   )r   Zfunc_or_msgr:   rc   rJ   r   r   )rb   r   r    __call__d  s    
zTimer.__call__c             C   s   | j S )N)rR   )r   r   r   r    	__float__{  s    zTimer.__float__c             C   s
   t | jS )N)intrR   )r   r   r   r    __int__~  s    zTimer.__int__c             C   s
   d| j  S )Nz%.3f)rR   )r   r   r   r    __str__  s    zTimer.__str__)NNNN)N)N)r$   r%   r&   r'   timeitZdefault_timerrP   rU   r   r   rK   rS   rT   rX   rY   r_   rd   re   rg   rh   r   r   r   r    rI      s   7

	
rI   c               @   s    e Zd ZdZdd Zdd ZdS )ChannelsFiltera  Provides 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!')
	c             G   s$   || _ t|| _dd |D | _d S )Nc             S   s   i | ]}t ||qS r   )rC   ).0nr   r   r    
<dictcomp>  s    z+ChannelsFilter.__init__.<locals>.<dictcomp>)namesrC   numlengths)r   rn   r   r   r    r     s    
zChannelsFilter.__init__c             C   s`   | j dkrdS xL| jD ]B}| j| }||jkr2dS |j|d|dkr|j| dkrdS qW dS )Nr   Tr@   F)ro   rn   rp   r5   rV   )r   r#   r5   Znlenr   r   r    filter  s    


zChannelsFilter.filterN)r$   r%   r&   r'   r   rq   r   r   r   r    rj     s   rj   c                   s>   e Zd Z fddZdd Zdd Zdd Zdd
dZ  ZS )CapturingLogHandlerc                s:   t t| j|d g | _t|tr0t|| _n|| _d S )N)r   )	r   rr   r   recordsr   r   r   r3   r.   )r   r.   r   )r   r   r    r     s
    
zCapturingLogHandler.__init__c             C   sL   | j j| _| j j| _| j j| _| j |  | j | j d| j _d| j _| S )NF)	r.   rF   original_disabledr   original_levelr2   original_propagater6   r7   )r   r   r   r    rY     s    


zCapturingLogHandler.__enter__c             C   s2   | j |  | j | j | j| j _| j| j _| S )N)r.   rE   r7   ru   rt   rF   rv   r2   )r   typevaluer]   r   r   r    r_     s
    

zCapturingLogHandler.__exit__c             C   s   | j | d S )N)rs   rD   )r   r#   r   r   r    emit  s    zCapturingLogHandler.emitNc             C   sT   dd l }||}x | jD ]}|| rdS qW |d krDd| }dsPt|d S )Nr   Tz(Pattern '%s' not found in logger records)recompilers   searchZ
getMessageAssertionError)r   ZregexprJ   rz   patternrr   r   r    assertRegex  s    
zCapturingLogHandler.assertRegex)N)	r$   r%   r&   r   rY   r_   ry   r   r(   r   r   )r   r    rr     s
   rr   c               @   s   e Zd ZdZedd ZdS )LogMixina   Mixin class that adds logging functionality to another class.

	You can define a new class that subclasses from ``LogMixin`` as well as
	other base classes through multiple inheritance.
	All instances of that class will have a ``log`` property that returns
	a ``logging.Logger`` named after their respective ``<module>.<class>``.

	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
	c             C   s2   t | ds,d| jj| jjf}t|| _| jS )N_logr@   )hasattrr8   r   r%   r$   r   r3   r   )r   r5   r   r   r    rZ     s
    
zLogMixin.logN)r$   r%   r&   r'   propertyrZ   r   r   r   r    r     s   r   c             C   s   t jd| |f |dd dS )z< Raise a warning about deprecated function argument 'name'. z%r is deprecated; %s   )category
stacklevelN)warningswarn)r5   rJ   r   r   r   r    deprecateArgument  s    r   c                s    fdd}|S )zD Decorator to raise a warning when a deprecated function is called. c                s   t   fdd}|S )Nc                 s$   t jdjf  dd | |S )Nz%r is deprecated; %s   )r   r   )r   r   r$   )r`   r:   )r   rb   rJ   r   r    rc     s    
z5deprecateFunction.<locals>.decorator.<locals>.wrapper)r   )rb   rc   )r   rJ   )rb   r    	decorator  s    z$deprecateFunction.<locals>.decoratorr   )rJ   r   r   r   )r   rJ   r    deprecateFunction	  s    r   __main__)Zoptionflags)r1   )!sysr   ri   	functoolsr   Zcollections.abcr   r   r   r   r   rM   r   Z	Formatterr	   r>   r4   objectrI   ZFilterrj   ZHandlerrr   r   UserWarningr   r   r$   ZdoctestexitZtestmodELLIPSISZfailedr   r   r   r    <module>   s.   B`
) %-+&
