[docs]classTracer:""" Tracer object. Args: threading_support (bool): Hooks the tracer into ``threading.settrace`` as well if True. """
[docs]def__init__(self,threading_support=None,profiling_mode=False):self._handler=Noneself._previous=Noneself._threading_previous=None#: True if threading support was enabled. Should be considered read-only.#:#: :type: boolself.threading_support=threading_support#: True if profiling mode was enabled. Should be considered read-only.#:#: :type: boolself.profiling_mode=profiling_mode#: Tracing depth (increases on calls, decreases on returns)#:#: :type: intself.depth=0#: A counter for total number of 'call' frames that this Tracer went through.#:#: :type: intself.calls=0
@propertydefhandler(self):""" The current predicate. Set via :func:`hunter.Tracer.trace`. """returnself._handler@propertydefprevious(self):""" The previous tracer, if any (whatever ``sys.gettrace()`` returned prior to :func:`hunter.Tracer.trace`). """returnself._previous
[docs]def__repr__(self):return'<hunter.tracer.Tracer at 0x{:x}: threading_support={}, {}{}{}{}>'.format(id(self),self.threading_support,'<stopped>'ifself._handlerisNoneelse'handler=',''ifself._handlerisNoneelserepr(self._handler),''ifself._previousisNoneelse', previous=',''ifself._previousisNoneelserepr(self._previous),)
[docs]def__call__(self,frame,kind,arg):""" The settrace function. .. note:: This always returns self (drills down) - as opposed to only drilling down when ``predicate(event)`` is True because it might match further inside. """ifself._handlerisnotNone:ifkind=='return'andself.depth>0:self.depth-=1event=Event(frame,kind,arg,self)try:self._handler(event)exceptExceptionasexc:traceback.print_exc(file=hunter._default_stream)hunter._default_stream.write(f'Disabling tracer because handler {self._handler!r} failed ({exc!r}) at {event!r}.\n\n')self.stop()returnifkind=='call':self.depth+=1self.calls+=1returnself
[docs]deftrace(self,predicate):""" Starts tracing with the given callable. Args: predicate (callable that accepts a single :obj:`~hunter.event.Event` argument): Return: self """self._handler=predicateifself.profiling_mode:ifself.threading_supportisNoneorself.threading_support:self._threading_previous=getattr(threading,'_profile_hook',None)threading.setprofile(self)self._previous=sys.getprofile()sys.setprofile(self)else:ifself.threading_supportisNoneorself.threading_support:self._threading_previous=getattr(threading,'_trace_hook',None)threading.settrace(self)self._previous=sys.gettrace()sys.settrace(self)returnself
[docs]defstop(self):""" Stop tracing. Reinstalls the :attr:`~hunter.tracer.Tracer.previous` tracer. """ifself._handlerisnotNone:ifself.profiling_mode:sys.setprofile(self._previous)self._handler=self._previous=Noneifself.threading_supportisNoneorself.threading_support:threading.setprofile(self._threading_previous)self._threading_previous=Noneelse:sys.settrace(self._previous)self._handler=self._previous=Noneifself.threading_supportisNoneorself.threading_support:threading.settrace(self._threading_previous)self._threading_previous=None
[docs]def__enter__(self):""" Does nothing. Users are expected to call :meth:`~hunter.tracer.Tracer.trace`. Returns: self """returnself
[docs]def__exit__(self,exc_type,exc_val,exc_tb):""" Wrapper around :meth:`~hunter.tracer.Tracer.stop`. Does nothing with the arguments. """self.stop()