diff --git a/python/pyarrow/src/arrow/python/common.h b/python/pyarrow/src/arrow/python/common.h index e36c0834fd424..bc567ef78e83a 100644 --- a/python/pyarrow/src/arrow/python/common.h +++ b/python/pyarrow/src/arrow/python/common.h @@ -188,7 +188,12 @@ class ARROW_PYTHON_EXPORT OwnedRef { return *this; } - ~OwnedRef() { reset(); } + ~OwnedRef() { + // GH-38626: destructor may be called after the Python interpreter is finalized. + if (Py_IsInitialized()) { + reset(); + } + } void reset(PyObject* obj) { Py_XDECREF(obj_); @@ -225,13 +230,11 @@ class ARROW_PYTHON_EXPORT OwnedRefNoGIL : public OwnedRef { explicit OwnedRefNoGIL(PyObject* obj) : OwnedRef(obj) {} ~OwnedRefNoGIL() { - // This destructor may be called after the Python interpreter is finalized. - // At least avoid spurious attempts to take the GIL when not necessary. - if (obj() == NULLPTR) { - return; + // GH-38626: destructor may be called after the Python interpreter is finalized. + if (Py_IsInitialized() && obj() != NULLPTR) { + PyAcquireGIL lock; + reset(); } - PyAcquireGIL lock; - reset(); } }; diff --git a/python/pyarrow/tests/test_misc.py b/python/pyarrow/tests/test_misc.py index 9b9dfdd554806..a48ac0c3cd81a 100644 --- a/python/pyarrow/tests/test_misc.py +++ b/python/pyarrow/tests/test_misc.py @@ -117,6 +117,19 @@ def test_runtime_info(): subprocess.check_call([sys.executable, "-c", code], env=env) +def test_import_at_shutdown(): + # GH-38626: importing PyArrow at interpreter shutdown would crash + code = """if 1: + import atexit + + def import_arrow(): + import pyarrow + + atexit.register(import_arrow) + """ + subprocess.check_call([sys.executable, "-c", code]) + + @pytest.mark.skipif(sys.platform == "win32", reason="Path to timezone database is not configurable " "on non-Windows platforms")