Usage#
Pile d’appel#
La pile d’appel (ou pile d’exécution ou call stack) mémorise les appels de fonctions. La premièrel ligne est le point d’entrée du programme. La suivante est la seconde fonction appelée. Si celle-ci en appelle une autre, une autre ligne est ajoutée et celle-ci demeure jusqu’à ce qu’elle est terminée son exécution. A chaque instant, la dernière ligne est la fonction en train de s’exécuter, les lignes précédentes définissent le chemin que l’ordinateur a suivi pour arriver jusque là.
<<<
import traceback
import sys
def foncA():
print("foncA begin")
foncB()
print("foncA end")
def foncB():
print("foncB begin")
foncC()
print("foncB end")
def foncC():
print("foncC begin")
try:
raise Exception("erreur volontaire")
except Exception:
print("Erreur")
print("\n".join(traceback.format_stack()))
print("foncC end")
foncA()
>>>
foncA begin
foncB begin
foncC begin
Erreur
File "somewhere/workspace/teachpyx/teachpyx_UT_39_std/_venv/lib/python3.9/site-packages/pyquickhelper/helpgen/process_sphinx_cmd.py", line 23, in <module>
main()
File "somewhere/workspace/teachpyx/teachpyx_UT_39_std/_venv/lib/python3.9/site-packages/pyquickhelper/helpgen/process_sphinx_cmd.py", line 19, in main
run_sphinx_build(sys.argv)
File "somewhere/workspace/teachpyx/teachpyx_UT_39_std/_venv/lib/python3.9/site-packages/pyquickhelper/helpgen/process_sphinx_cmd.py", line 15, in run_sphinx_build
build_main(argv=argv[1:])
File "/usr/local/lib/python3.9/site-packages/sphinx/cmd/build.py", line 321, in main
return build_main(argv)
File "/usr/local/lib/python3.9/site-packages/sphinx/cmd/build.py", line 285, in build_main
app.build(args.force_all, args.filenames)
File "/usr/local/lib/python3.9/site-packages/sphinx/application.py", line 353, in build
self.builder.build_update()
File "/usr/local/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 311, in build_update
self.build(to_build,
File "/usr/local/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 328, in build
updated_docnames = set(self.read())
File "/usr/local/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 435, in read
self._read_serial(docnames)
File "/usr/local/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 456, in _read_serial
self.read_doc(docname)
File "/usr/local/lib/python3.9/site-packages/sphinx/builders/__init__.py", line 512, in read_doc
publisher.publish()
File "/usr/local/lib/python3.9/site-packages/docutils/core.py", line 224, in publish
self.document = self.reader.read(self.source, self.parser,
File "/usr/local/lib/python3.9/site-packages/sphinx/io.py", line 108, in read
self.parse()
File "/usr/local/lib/python3.9/site-packages/docutils/readers/__init__.py", line 76, in parse
self.parser.parse(self.input, document)
File "/usr/local/lib/python3.9/site-packages/sphinx/parsers.py", line 80, in parse
self.statemachine.run(inputlines, document, inliner=self.inliner)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 169, in run
results = StateMachineWS.run(self, input_lines, input_offset,
File "/usr/local/lib/python3.9/site-packages/docutils/statemachine.py", line 233, in run
context, next_state, result = self.check_line(
File "/usr/local/lib/python3.9/site-packages/docutils/statemachine.py", line 445, in check_line
return method(match, context, next_state)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 3024, in text
self.section(title.lstrip(), source, style, lineno + 1, messages)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 325, in section
self.new_subsection(title, lineno, messages)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection
newabsoffset = self.nested_parse(
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse
state_machine.run(block, input_offset, memo=self.memo,
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 195, in run
results = StateMachineWS.run(self, input_lines, input_offset)
File "/usr/local/lib/python3.9/site-packages/docutils/statemachine.py", line 233, in run
context, next_state, result = self.check_line(
File "/usr/local/lib/python3.9/site-packages/docutils/statemachine.py", line 445, in check_line
return method(match, context, next_state)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2785, in underline
self.section(title, source, style, lineno - 1, messages)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 325, in section
self.new_subsection(title, lineno, messages)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 391, in new_subsection
newabsoffset = self.nested_parse(
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 279, in nested_parse
state_machine.run(block, input_offset, memo=self.memo,
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 195, in run
results = StateMachineWS.run(self, input_lines, input_offset)
File "/usr/local/lib/python3.9/site-packages/docutils/statemachine.py", line 233, in run
context, next_state, result = self.check_line(
File "/usr/local/lib/python3.9/site-packages/docutils/statemachine.py", line 445, in check_line
return method(match, context, next_state)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2355, in explicit_markup
nodelist, blank_finish = self.explicit_construct(match)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2367, in explicit_construct
return method(self, expmatch)
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2104, in directive
return self.run_directive(
File "/usr/local/lib/python3.9/site-packages/docutils/parsers/rst/states.py", line 2154, in run_directive
result = directive_instance.run()
File "somewhere/workspace/teachpyx/teachpyx_UT_39_std/_venv/lib/python3.9/site-packages/pyquickhelper/sphinxext/sphinx_runpython_extension.py", line 568, in run
out, err, context = run_python_script(script, comment=comment, setsysvar=p['setsysvar'],
File "somewhere/workspace/teachpyx/teachpyx_UT_39_std/_venv/lib/python3.9/site-packages/pyquickhelper/sphinxext/sphinx_runpython_extension.py", line 229, in run_python_script
exec(obj, globs, loc)
File "", line 26, in <module>
File "", line 25, in run_python_script_140112496841408
File "", line 8, in foncA
File "", line 13, in foncB
File "", line 22, in foncC
foncC end
foncB end
foncA end
Récupération de la pile d’appel#
Le module traceback permet de récupérer la pile d’appels lorsqu’une exception survient.
<<<
def raise_exception():
raise Exception("an error was raised")
try:
insidefe()
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
print("".join(traceback.format_tb(exc_traceback)))
>>>
File "", line 7, in run_python_script_140112496871488
Il est possible de récupérer la liste des appels de fonctions avec la fonction extract_tb. Cette information est précieuse pour écrire un test qui vérifie qu’une erreur s’est bien produite à un endroit particulier, de détecter les cas particuliers comme les boucles infinies ou d’améliorer un message d’erreur en cas de besoin (lire How do I write Flask’s excellent debug log message to a file in production?).
Message d’erreur plus explicite#
Lorsqu’une erreur se produit dans une librairie de Python, le message ne mentionne aucune information à propos du code qui l’a provoquée.
<<<
import math
ensemble = [1, 0, 2]
s = 0
for e in ensemble:
s += math.log(e)
>>>
[runpythonerror]
Traceback (most recent call last):
exec(obj, globs, loc)
File "", line 8, in <module>
File "", line 7, in run_python_script_140112496590784
ValueError: math domain error
Typiquement dans ce cas précis, on ne sait pas quel est l’indice de l’élément qui a provoqué l’erreur. On utilise alors un mécanisme qui permet d’ajouter une erreur sans perdre les informations l’exception original
<<<
import math
ensemble = [1, 0, 2]
s = 0
for i, e in enumerate(ensemble):
try:
s += math.log(e)
except Exception as exc:
raise Exception("Issue with element {0}".format(i)) from exc
>>>
[runpythonerror]
Traceback (most recent call last):
File "", line 8, in run_python_script_140112495973888
ValueError: math domain error
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
exec(obj, globs, loc)
File "", line 11, in <module>
File "", line 10, in run_python_script_140112495973888
Exception: Issue with element 1
La dernière partie de la dernière ligne est importante :
from exc
. langage garde ainsi la trace de la première
exception.
Conventions#
Erreur ou code d’erreur#
A faire: terminer la section Erreur ou code d’erreur
parler aussi de coûts d’une exception, libération des ressources