Как я могу получить информацию об исключении после того, как вызов PyRun_String() возвращает NULL?

Я пытаюсь запустить следующий код:

Py_Initialize();
PyObject *py_main = PyImport_AddModule("__main__");
PyObject *py_dict = PyModule_GetDict(py_main);
PyObject *ret = PyRun_String(SOME_PYTHON_CODE, Py_file_input, py_dict, py_dict);

Но кажется, что где-то в моем сгенерированном коде Python (SOME_PYTHON_CODE) есть ошибка, и поэтому ret выходит как NULL, указывающее, что было возбуждено исключение. Как я могу получить доступ к этому исключению?


person Matt    schedule 06.08.2014    source источник


Ответы (2)


Ты можешь сделать:

PyErr_Print();

Чтобы распечатать стандартную трассировку стека при стандартной ошибке. Есть и другие, более точно настроенные вызовы функций для обработки ошибок, но я считаю, что это самый простой подход.

И вот вопрос/ответ о доступе к объектам трассировки . Один из ответов показывает, как скопировать обратную трассировку в строку C, которую затем можно записать в файл (или графический интерфейс в вашем случае).

person mshildt    schedule 06.08.2014
comment
Одна из проблем, с которыми я сталкиваюсь, заключается в том, что я не могу подключить stdin/stdout/stderr python к окну консоли (это приложение с графическим интерфейсом, и мне пришлось вручную открывать окно консоли). Так что PyErr_Print() мне совсем не помог бы. - person Matt; 06.08.2014
comment
Вы можете получить фактический объект трассировки (я обновил свой ответ, чтобы показать, как это сделать). Затем просмотрите поля в объекте трассировки, чтобы выяснить, что произошло. Однако я не очень хорошо знаком с объектами трассировки. - person mshildt; 06.08.2014
comment
Я только что пытался это сделать, но кажется, что PyException_GetTraceback не определено в Python.h. - person Matt; 06.08.2014
comment
@Matt О, вы, должно быть, используете Python 2. Поскольку в вашем вопросе не было сказано, я предположил, что вы используете последнюю версию (Python 3). В этом случае, я думаю, вам нужно будет использовать PyErr_Fetch(). - person mshildt; 06.08.2014
comment
Это довольно плохое предположение, так как Python 2 по-прежнему используется намного шире, но спасибо! - person Matt; 07.08.2014
comment
Этот ответ кажется либо неверным, либо основанным на старом поведении API, по крайней мере, он вообще не работает в python 3.8: PyErr_Occurred вернет только type исключения, а не само исключение. Попытка вызвать PyException_GetTraceback для типа обречена на провал. Нужно просто вызвать PyErr_Fetch, чтобы получить исключение вместе с объектом трассировки. В документации об этом очень ясно сказано. - person ceztko; 13.04.2021

Поскольку вы не указали количество операторов SOME_PYTHON_CODE, может возникнуть другая проблема: согласно эта страница учебника по Boost Python, вывод PyRun_String также зависит от параметра start:

  • Py_eval_input для интерпретации изолированных выражений
  • Py_file_input для интерпретации последовательностей операторов
  • Py_single_input для интерпретации одного оператора

Далее говорится:

При использовании Py_eval_input входная строка должна содержать одно выражение, и возвращается его результат. При использовании Py_file_input строка может содержать произвольное количество операторов, и возвращается None. Py_single_input работает так же, как Py_file_input, но принимает только один оператор.

Поэтому, если вы используете Py_file_input в своем вызове PyRun_String, вы всегда будете получать None. Вместо этого вы можете использовать Py_single_input.

person melle    schedule 23.11.2015