diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 84035eb3..2ee46912 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -455,6 +455,7 @@ PYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration) PYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError) PYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError) PYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError) +PYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError) PYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError) PYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or handle::call fail due to a type casting error PYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 686fe536..f7d46cf3 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -567,7 +567,7 @@ public: static module import(const char *name) { PyObject *obj = PyImport_ImportModule(name); if (!obj) - pybind11_fail("Module \"" + std::string(name) + "\" not found!"); + throw import_error("Module \"" + std::string(name) + "\" not found!"); return module(obj, false); } }; @@ -1344,15 +1344,27 @@ PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) { auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" "); auto line = sep.attr("join")(strings); - auto file = kwargs.contains("file") ? kwargs["file"].cast() - : module::import("sys").attr("stdout"); + object file; + if (kwargs.contains("file")) { + file = kwargs["file"].cast(); + } else { + try { + file = module::import("sys").attr("stdout"); + } catch (const import_error &) { + /* If print() is called from code that is executed as + part of garbage collection during interpreter shutdown, + importing 'sys' can fail. Give up rather than crashing the + interpreter in this case. */ + return; + } + } + auto write = file.attr("write"); write(line); write(kwargs.contains("end") ? kwargs["end"] : cast("\n")); - if (kwargs.contains("flush") && kwargs["flush"].cast()) { + if (kwargs.contains("flush") && kwargs["flush"].cast()) file.attr("flush")(); - } } NAMESPACE_END(detail)