studio - python debugger portable
Cómo limitar el rastreo de python a archivos específicos (3)
Como otros sugirieron, podrías usar sys.excepthook
:
Esta función imprime un seguimiento dado y una excepción a sys.stderr .
Cuando se produce una excepción y no se captura, el intérprete llama a sys.excepthook con tres argumentos, la clase de excepción, la instancia de excepción y un objeto de rastreo. En una sesión interactiva, esto sucede justo antes de que se devuelva el control al indicador; en un programa Python esto sucede justo antes de que el programa salga. El manejo de tales excepciones de nivel superior se puede personalizar asignando otra función de tres argumentos a sys.excepthook .
(énfasis mío)
Es posible filtrar un rastreo extraído por extract_tb
(o funciones similares del módulo de traceback
) en función de directorios específicos.
Dos funciones que pueden ayudar:
from os.path import join, abspath
from traceback import extract_tb, format_list, format_exception_only
def spotlight(*show):
'''''' Return a function to be set as new sys.excepthook.
It will SHOW traceback entries for files from these directories. ''''''
show = tuple(join(abspath(p), '''') for p in show)
def _check_file(name):
return name and name.startswith(show)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''''.join(fmt), end='''', file=sys.stderr)
return _print
def shadow(*hide):
'''''' Return a function to be set as new sys.excepthook.
It will HIDE traceback entries for files from these directories. ''''''
hide = tuple(join(abspath(p), '''') for p in hide)
def _check_file(name):
return name and not name.startswith(hide)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''''.join(fmt), end='''', file=sys.stderr)
return _print
Ambos usan el traceback.extract_tb
. Devuelve "una lista de entradas de seguimiento de pila" preprocesadas "extraídas del objeto de rastreo" ; todos ellos son instancias de traceback.FrameSummary
(una tupla con nombre). Cada objeto traceback.FrameSummary
tiene un campo de filename
que almacena la ruta absoluta del archivo correspondiente. Verificamos si comienza con alguna de las rutas de directorio proporcionadas como argumentos de función separados para determinar si necesitaremos excluir la entrada (o conservarla).
Aquí hay un ejemplo :
El módulo de enum
de la biblioteca estándar no permite reutilizar claves,
import enum
enum.Enum(''Faulty'', ''a a'', module=__name__)
rendimientos
Traceback (most recent call last):
File "/home/vaultah/so/shadows/main.py", line 23, in <module>
enum.Enum(''Faulty'', ''a a'', module=__name__)
File "/home/vaultah/cpython/Lib/enum.py", line 243, in __call__
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
File "/home/vaultah/cpython/Lib/enum.py", line 342, in _create_
classdict[member_name] = member_value
File "/home/vaultah/cpython/Lib/enum.py", line 72, in __setitem__
raise TypeError(''Attempted to reuse key: %r'' % key)
TypeError: Attempted to reuse key: ''a''
Podemos restringir las entradas de seguimiento de pila a nuestro código (en /home/vaultah/so/shadows/main.py ).
import sys, enum
sys.excepthook = spotlight(''/home/vaultah/so/shadows'')
enum.Enum(''Faulty'', ''a a'', module=__name__)
y
import sys, enum
sys.excepthook = shadow(''/home/vaultah/cpython/Lib'')
enum.Enum(''Faulty'', ''a a'', module=__name__)
dar el mismo resultado:
File "/home/vaultah/so/shadows/main.py", line 22, in <module>
enum.Enum(''Faulty'', ''a a'', module=__name__)
TypeError: Attempted to reuse key: ''a''
Hay una manera de excluir todos los directorios del sitio (donde se instalan los paquetes de terceros - vea site.getsitepackages
)
import sys, site, jinja2
sys.excepthook = shadow(*site.getsitepackages())
jinja2.Template(''{%}'')
# jinja2.exceptions.TemplateSyntaxError: unexpected ''}''
# Generates ~30 lines, but will only display 4
Nota: No olvide restaurar sys.excepthook desde sys .__ excepthook__ . Desafortunadamente, no podrá "restaurar parches" mediante un administrador de contexto.
Escribo mucho código Python que utiliza bibliotecas externas. Con frecuencia escribiré un error, y cuando ejecuto el código obtengo una larga y larga respuesta en la consola de Python. El 99.999999% del tiempo se debe a un error de codificación en mi código, no a un error en el paquete. Pero el rastro regresa hasta la línea de error en el código del paquete, y o bien se necesita mucho desplazamiento en el rastreo para encontrar el código que escribí, o el rastreo está tan profundo en el paquete que mi propio código no lo hace. Ni siquiera aparecen en la traza.
¿Hay alguna forma de "poner en una caja negra" el código del paquete, o de alguna manera solo mostrar las líneas de rastreo de mi código? Me gustaría poder especificar en el sistema los directorios o archivos desde los que deseo ver el rastreo.
traceback.extract_tb (tb) devolvería una tupla de marcos de error en el formato (archivo, línea_no, tipo, error_statement), puede jugar con eso para formatear la traza. Consulte también https://pymotw.com/2/sys/exceptions.html
import sys
import traceback
def handle_exception(ex_type, ex_info, tb):
print ex_type, ex_info, traceback.extract_tb(tb)
sys.excepthook = handle_exception
Para imprimir su propio stacktrace, deberá manejar usted mismo todas las excepciones no manejadas; Así es como el sys.excepthook
vuelve práctico.
La firma para esta función es sys.excepthook(type, value, traceback)
y su trabajo es:
Esta función imprime un
sys.stderr
dado y una excepción asys.stderr
.
Por lo tanto, siempre que pueda jugar con el rastreo y solo extraer la parte que le interesa debería estar bien. Los marcos de prueba lo hacen con mucha frecuencia; tienen funciones de assert
personalizadas que generalmente no aparecen en el rastreo, en otras palabras, omiten los marcos que pertenecen al marco de prueba. Además, en esos casos, las pruebas suelen iniciarse también en el marco de la prueba.
Terminas con un rastreo que se ve así:
[ custom assert code ]
+ ... [ code under test ] ...
+ [ test runner code ]
Cómo identificar su código.
Puedes agregar un global a tu código:
__mycode = True
Luego para identificar los marcos:
def is_mycode(tb):
globals = tb.tb_frame.f_globals
return globals.has_key(''__mycode'')
Cómo extraer tus marcos.
- omita los marcos que no le interesan (por ejemplo, código de confirmación personalizado)
- identificar cuántos marcos forman parte de su código ->
length
extraer marcos de
length
def mycode_traceback_levels(tb): length = 0 while tb and is_mycode(tb): tb = tb.tb_next length += 1 return length
Controlador de ejemplo.
def handle_exception(type, value, tb):
# 1. skip custom assert code, e.g.
# while tb and is_custom_assert_code(tb):
# tb = tb.tb_next
# 2. only display your code
length = mycode_traceback_levels(tb)
print ''''.join(traceback.format_exception(type, value, tb, length))
instalar el controlador:
sys.excepthook = handle_exception
¿Qué sigue?
Puede ajustar la length
para agregar uno o más niveles si aún desea información sobre dónde se encuentra la falla fuera de su propio código.
vea también https://gist.github.com/dnozay/b599a96dc2d8c69b84c6