Repository: duckdb/duckdb (language: python)

Issue:
Unit tests of built Python package fail on OSX (in conda-forge build)
### What happens?

Running the unit tests with a built `python-duckdb` on conda-forge fails with a segmentation fault in the `tools/pythonpkg/tests/fast/test_filesystem.py::TestPythonFilesystem::test_database_attach`

See the following stack trace:

```
tools/pythonpkg/tests/fast/test_filesystem.py::TestPythonFilesystem::test_database_attach Assertion failed: (!py::gil_check()), function Seek, file src/pyfilesystem.cpp, line 156.
Process 42452 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = hit program assert
    frame #4: 0x0000000106c640ec duckdb.cpython-311-darwin.so`duckdb::PythonFilesystem::Seek(duckdb::FileHandle&, unsigned long long) + 212
duckdb.cpython-311-darwin.so`duckdb::PythonFilesystem::Seek:
->  0x106c640ec <+212>: mov    w0, #0x1 ; =1
    0x106c640f0 <+216>: bl     0x106cc0fc0    ; symbol stub for: PyErr_PrintEx
    0x106c640f4 <+220>: mov    w0, #0x10 ; =16
    0x106c640f8 <+224>: bl     0x106cc1bd8    ; symbol stub for: __cxa_allocate_exception
Target 0: (python) stopped.
(lldb) bt all
* thread #1, queue = 'com.apple.main-thread', stop reason = hit program assert
    frame #0: 0x000000018a0655d0 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x000000018a09dc20 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x0000000189faaa30 libsystem_c.dylib`abort + 180
    frame #3: 0x0000000189fa9d20 libsystem_c.dylib`__assert_rtn + 284
  * frame #4: 0x0000000106c640ec duckdb.cpython-311-darwin.so`duckdb::PythonFilesystem::Seek(duckdb::FileHandle&, unsigned long long) + 212
    frame #5: 0x0000000106c635cc duckdb.cpython-311-darwin.so`duckdb::PythonFilesystem::Write(duckdb::FileHandle&, void*, long long, unsigned long long) + 48
    frame #6: 0x0000000106a4f238 duckdb.cpython-311-darwin.so`duckdb::BlockManager::ConvertToPersistent(long long, duckdb::shared_ptr<duckdb::BlockHandle, true>) + 668
    frame #7: 0x0000000106b19c8c duckdb.cpython-311-darwin.so`duckdb::ColumnSegment::ConvertToPersistent(duckdb::optional_ptr<duckdb::BlockManager, true>, long long) + 124
    frame #8: 0x0000000106b1991c duckdb.cpython-311-darwin.so`duckdb::PartialBlockForCheckpoint::Flush(unsigned long long) + 360
    frame #9: 0x0000000106a11f04 duckdb.cpython-311-darwin.so`duckdb::SingleFileCheckpointWriter::WriteTable(duckdb::TableCatalogEntry&, duckdb::Serializer&) + 444
    frame #10: 0x0000000106a0f308 duckdb.cpython-311-darwin.so`duckdb::SingleFileCheckpointWriter::CreateCheckpoint() + 2656
    frame #11: 0x0000000106a27a24 duckdb.cpython-311-darwin.so`duckdb::SingleFileStorageManager::CreateCheckpoint(duckdb::CheckpointOptions) + 484
    frame #12: 0x00000001066ef59c duckdb.cpython-311-darwin.so`duckdb::AttachedDatabase::Close() + 304
    frame #13: 0x000000010670865c duckdb.cpython-311-darwin.so`duckdb::DatabaseManager::ResetDatabases(duckdb::unique_ptr<duckdb::TaskScheduler, std::__1::default_delete<duckdb::TaskScheduler>, true>&) + 156
    frame #14: 0x0000000106708370 duckdb.cpython-311-darwin.so`duckdb::DatabaseInstance::~DatabaseInstance() + 40
    frame #15: 0x00000001067741d4 duckdb.cpython-311-darwin.so`std::__1::__shared_ptr_emplace<duckdb::DuckDB, std::__1::allocator<duckdb::DuckDB>>::__on_zero_shared() + 64
    frame #16: 0x0000000106c1ca1c duckdb.cpython-311-darwin.so`duckdb::DuckDBPyConnection::Close() + 100
    frame #17: 0x0000000106c1c7f4 duckdb.cpython-311-darwin.so`duckdb::DuckDBPyConnection::Exit(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&) + 24
    frame #18: 0x0000000106c4d92c duckdb.cpython-311-darwin.so`void pybind11::cpp_function::initialize<void (*&)(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&), void, duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&, pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg>(void (*&)(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&), void (*)(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&), pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&, pybind11::arg const&, pybind11::arg const&, pybind11::arg const&)::'lambda'(pybind11::detail::function_call&)::operator()(pybind11::detail::function_call&) const + 140
    frame #19: 0x0000000106c4d878 duckdb.cpython-311-darwin.so`void pybind11::cpp_function::initialize<void (*&)(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&), void, duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&, pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg>(void (*&)(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&), void (*)(duckdb::DuckDBPyConnection&, pybind11::object const&, pybind11::object const&, pybind11::object const&), pybind11::name const&, pybind11::is_method const&, pybind11::sibling const&, pybind11::arg const&, pybind11::arg const&, pybind11::arg const&)::'lambda'(pybind11::detail::function_call&)::__invoke(pybind11::detail::function_call&) + 40
    frame #20: 0x0000000106b755a8 duckdb.cpython-311-darwin.so`pybind11::cpp_function::dispatcher(_object*, _object*, _object*) + 4312
    frame #21: 0x00000001000b7f4c python`cfunction_call + 124
    frame #22: 0x00000001000606f0 python`_PyObject_MakeTpCall + 332
    frame #23: 0x0000000100064200 python`method_vectorcall + 276
    frame #24: 0x0000000100060ffc python`PyObject_Vectorcall + 76
    frame #25: 0x0000000100162e3c python`_PyEval_EvalFrameDefault + 46484
    frame #26: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #27: 0x0000000100064198 python`method_vectorcall + 172
    frame #28: 0x0000000100060e68 python`_PyVectorcall_Call + 132
    frame #29: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #30: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #31: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #32: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #33: 0x00000001000608b8 python`_PyObject_FastCallDictTstate + 156
    frame #34: 0x00000001000617f0 python`_PyObject_Call_Prepend + 176
    frame #35: 0x00000001000db278 python`slot_tp_call + 172
    frame #36: 0x00000001000606f0 python`_PyObject_MakeTpCall + 332
    frame #37: 0x0000000100162e3c python`_PyEval_EvalFrameDefault + 46484
    frame #38: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #39: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #40: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #41: 0x00000001000608b8 python`_PyObject_FastCallDictTstate + 156
    frame #42: 0x00000001000617f0 python`_PyObject_Call_Prepend + 176
    frame #43: 0x00000001000db278 python`slot_tp_call + 172
    frame #44: 0x000000010006126c python`_PyObject_Call + 236
    frame #45: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #46: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #47: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #48: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #49: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #50: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #51: 0x00000001000608b8 python`_PyObject_FastCallDictTstate + 156
    frame #52: 0x00000001000617f0 python`_PyObject_Call_Prepend + 176
    frame #53: 0x00000001000db278 python`slot_tp_call + 172
    frame #54: 0x00000001000606f0 python`_PyObject_MakeTpCall + 332
    frame #55: 0x0000000100162e3c python`_PyEval_EvalFrameDefault + 46484
    frame #56: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #57: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #58: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #59: 0x00000001000608b8 python`_PyObject_FastCallDictTstate + 156
    frame #60: 0x00000001000617f0 python`_PyObject_Call_Prepend + 176
    frame #61: 0x00000001000db278 python`slot_tp_call + 172
    frame #62: 0x00000001000606f0 python`_PyObject_MakeTpCall + 332
    frame #63: 0x0000000100162e3c python`_PyEval_EvalFrameDefault + 46484
    frame #64: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #65: 0x0000000100164dac python`_PyEval_EvalFrameDefault + 54532
    frame #66: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #67: 0x00000001000608b8 python`_PyObject_FastCallDictTstate + 156
    frame #68: 0x00000001000617f0 python`_PyObject_Call_Prepend + 176
    frame #69: 0x00000001000db278 python`slot_tp_call + 172
    frame #70: 0x00000001000606f0 python`_PyObject_MakeTpCall + 332
    frame #71: 0x0000000100162e3c python`_PyEval_EvalFrameDefault + 46484
    frame #72: 0x00000001001568f4 python`PyEval_EvalCode + 220
    frame #73: 0x00000001001526a4 python`builtin_exec + 1156
    frame #74: 0x00000001000b8c68 python`cfunction_vectorcall_FASTCALL_KEYWORDS + 168
    frame #75: 0x0000000100060ffc python`PyObject_Vectorcall + 76
    frame #76: 0x0000000100162e3c python`_PyEval_EvalFrameDefault + 46484
    frame #77: 0x00000001001674c8 python`_PyEval_Vector + 184
    frame #78: 0x00000001001e2588 python`pymain_run_module + 272
    frame #79: 0x00000001001e1f74 python`Py_RunMain + 2476
    frame #80: 0x00000001001e3050 python`pymain_main + 1252
    frame #81: 0x0000000100003398 python`main + 56
    frame #82: 0x0000000189d13154 dyld`start + 2476
  thread #2
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #3
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #4
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #5
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #6
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #7
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #8
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #9
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #10
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #11
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #12
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #13
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #14
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #15
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #16
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #17
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #18
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #19
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #20
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #21
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #22
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
  thread #23
    frame #0: 0x000000018a05cd50 libsystem_kernel.dylib`semaphore_wait_trap + 8
    frame #1: 0x0000000106898230 duckdb.cpython-311-darwin.so`duckdb::TaskScheduler::ExecuteForever(std::__1::atomic<bool>*) + 608
    frame #2: 0x000000010689ecec duckdb.cpython-311-darwin.so`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(duckdb::TaskScheduler*, std::__1::atomic<bool>*), duckdb::TaskScheduler*, std::__1::atomic<bool>*>>(void*) + 72
    frame #3: 0x000000018a09df94 libsystem_pthread.dylib`_pthread_start + 136
(lldb)
```

### To Reproduce

To reproduce, you can build the conda-forge feedstock from the PR in https://github.com/conda-forge/python-duckdb-feedstock/pull/114 using `conda-build -m .ci_support/osx_arm64_python3.11.____cpython.yaml recipe`

### OS:

OSX

### DuckDB Version:

1.1.1

### DuckDB Client:

Python

### Hardware:

OSX (all architectures)

### Full Name:

Uwe Korn

### Affiliation:

conda-forge (in this case)

### What is the latest build you tested with? If possible, we recommend testing with the latest nightly build.

I have tested with a stable release

### Did you include all relevant data sets for reproducing the issue?

Not applicable - the reproduction does not require a data set

### Did you include all code required to reproduce the issue?

- [X] Yes, I have

### Did you include all relevant configuration (e.g., CPU architecture, Python version, Linux distribution) to reproduce the issue?

- [X] Yes, I have


Discussion / hints:
@xhochy thanks, we'll take a look!

Fix patch:
diff --git a/tools/pythonpkg/src/include/duckdb_python/pyconnection/pyconnection.hpp b/tools/pythonpkg/src/include/duckdb_python/pyconnection/pyconnection.hpp
index 13acaffe5883..5850eb246267 100644
--- a/tools/pythonpkg/src/include/duckdb_python/pyconnection/pyconnection.hpp
+++ b/tools/pythonpkg/src/include/duckdb_python/pyconnection/pyconnection.hpp
@@ -324,7 +324,6 @@ struct DuckDBPyConnection : public enable_shared_from_this<DuckDBPyConnection> {
 
 private:
 	PathLike GetPathLike(const py::object &object);
-	unique_lock<std::mutex> AcquireConnectionLock();
 	ScalarFunction CreateScalarUDF(const string &name, const py::function &udf, const py::object &parameters,
 	                               const shared_ptr<DuckDBPyType> &return_type, bool vectorized,
 	                               FunctionNullHandling null_handling, PythonExceptionHandling exception_handling,
diff --git a/tools/pythonpkg/src/pyconnection.cpp b/tools/pythonpkg/src/pyconnection.cpp
index 7c52e0241502..39b8dcf30a32 100644
--- a/tools/pythonpkg/src/pyconnection.cpp
+++ b/tools/pythonpkg/src/pyconnection.cpp
@@ -416,6 +416,7 @@ void DuckDBPyConnection::Initialize(py::handle &m) {
 }
 
 shared_ptr<DuckDBPyConnection> DuckDBPyConnection::ExecuteMany(const py::object &query, py::object params_p) {
+	py::gil_scoped_acquire gil;
 	con.SetResult(nullptr);
 	if (params_p.is_none()) {
 		params_p = py::list();
@@ -541,6 +542,7 @@ unique_ptr<PreparedStatement> DuckDBPyConnection::PrepareQuery(unique_ptr<SQLSta
 	auto &connection = con.GetConnection();
 	unique_ptr<PreparedStatement> prep;
 	{
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release release;
 		unique_lock<mutex> lock(py_connection_lock);
 
@@ -561,6 +563,7 @@ unique_ptr<QueryResult> DuckDBPyConnection::ExecuteInternal(PreparedStatement &p
 	auto named_values = TransformPreparedParameters(prep, params);
 	unique_ptr<QueryResult> res;
 	{
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release release;
 		unique_lock<std::mutex> lock(py_connection_lock);
 
@@ -598,6 +601,7 @@ shared_ptr<DuckDBPyConnection> DuckDBPyConnection::ExecuteFromString(const strin
 }
 
 shared_ptr<DuckDBPyConnection> DuckDBPyConnection::Execute(const py::object &query, py::object params) {
+	py::gil_scoped_acquire gil;
 	con.SetResult(nullptr);
 
 	auto statements = GetStatements(query);
@@ -877,6 +881,7 @@ unique_ptr<DuckDBPyRelation> DuckDBPyConnection::ReadJSON(
 		auto_detect = true;
 	}
 
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release gil;
 	auto read_json_relation =
 	    make_shared_ptr<ReadJSONRelation>(connection.context, name, std::move(options), auto_detect);
@@ -1387,6 +1392,7 @@ unique_ptr<DuckDBPyRelation> DuckDBPyConnection::ReadCSV(const py::object &name_
 
 	// Create the ReadCSV Relation using the 'options'
 
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release gil;
 	auto read_csv_p = connection.ReadCSV(name, std::move(bind_parameters));
 	auto &read_csv = read_csv_p->Cast<ReadCSVRelation>();
@@ -1399,6 +1405,7 @@ unique_ptr<DuckDBPyRelation> DuckDBPyConnection::ReadCSV(const py::object &name_
 
 void DuckDBPyConnection::ExecuteImmediately(vector<unique_ptr<SQLStatement>> statements) {
 	auto &connection = con.GetConnection();
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release release;
 	if (statements.empty()) {
 		return;
@@ -1443,6 +1450,7 @@ unique_ptr<DuckDBPyRelation> DuckDBPyConnection::RunQuery(const py::object &quer
 	if (py::none().is(params)) {
 		// FIXME: currently we can't create relations with prepared parameters
 		{
+			D_ASSERT(py::gil_check());
 			py::gil_scoped_release gil;
 			auto statement_type = last_statement->type;
 			switch (statement_type) {
@@ -1557,6 +1565,7 @@ unique_ptr<DuckDBPyRelation> DuckDBPyConnection::FromParquet(const string &file_
 		}
 		named_parameters["compression"] = Value(py::str(compression));
 	}
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release gil;
 	return make_uniq<DuckDBPyRelation>(connection.TableFunction("parquet_scan", params, named_parameters)->Alias(name));
 }
@@ -1646,6 +1655,7 @@ shared_ptr<DuckDBPyConnection> DuckDBPyConnection::UnregisterPythonObject(const
 	if (!registered_objects.count(name)) {
 		return shared_from_this();
 	}
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release release;
 	// FIXME: DROP TEMPORARY VIEW? doesn't exist?
 	connection.Query("DROP VIEW \"" + name + "\"");
@@ -1691,6 +1701,8 @@ int DuckDBPyConnection::GetRowcount() {
 
 void DuckDBPyConnection::Close() {
 	con.SetResult(nullptr);
+	D_ASSERT(py::gil_check());
+	py::gil_scoped_release release;
 	con.SetConnection(nullptr);
 	con.SetDatabase(nullptr);
 	// https://peps.python.org/pep-0249/#Connection.close
@@ -1783,6 +1795,9 @@ void DuckDBPyConnection::Cursors::ClearCursors() {
 			// The cursor has already been closed
 			continue;
 		}
+		// This is *only* needed because we have a py::gil_scoped_release in Close, so it *needs* the GIL in order to
+		// release it don't ask me why it can't just realize there is no GIL and move on
+		py::gil_scoped_acquire gil;
 		cursor->Close();
 	}
 
@@ -1939,6 +1954,7 @@ static shared_ptr<DuckDBPyConnection> FetchOrCreateInstance(const string &databa
 	bool cache_instance = database_path != ":memory:" && !database_path.empty();
 	config.replacement_scans.emplace_back(PythonReplacementScan::Replace);
 	{
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release release;
 		unique_lock<mutex> lock(res->py_connection_lock);
 		auto database =
@@ -2195,14 +2211,4 @@ bool DuckDBPyConnection::IsAcceptedArrowObject(const py::object &object) {
 	return DuckDBPyConnection::GetArrowType(object) != PyArrowObjectType::Invalid;
 }
 
-unique_lock<std::mutex> DuckDBPyConnection::AcquireConnectionLock() {
-	// we first release the gil and then acquire the connection lock
-	unique_lock<std::mutex> lock(py_connection_lock, std::defer_lock);
-	{
-		py::gil_scoped_release release;
-		lock.lock();
-	}
-	return lock;
-}
-
 } // namespace duckdb
diff --git a/tools/pythonpkg/src/pyrelation.cpp b/tools/pythonpkg/src/pyrelation.cpp
index 9775deb9c110..b89a8e74479e 100644
--- a/tools/pythonpkg/src/pyrelation.cpp
+++ b/tools/pythonpkg/src/pyrelation.cpp
@@ -58,10 +58,8 @@ bool DuckDBPyRelation::CanBeRegisteredBy(shared_ptr<ClientContext> &con) {
 }
 
 DuckDBPyRelation::~DuckDBPyRelation() {
-	// FIXME: It makes sense to release the GIL here, but it causes a crash
-	// because pybind11's gil_scoped_acquire and gil_scoped_release can not be nested
-	// The Relation will need to call the destructor of the ExternalDependency, which might need to hold the GIL
-	// py::gil_scoped_release gil;
+	D_ASSERT(py::gil_check());
+	py::gil_scoped_release gil;
 	rel.reset();
 }
 
@@ -780,6 +778,7 @@ static unique_ptr<QueryResult> PyExecuteRelation(const shared_ptr<Relation> &rel
 		return nullptr;
 	}
 	auto context = rel->context.GetContext();
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release release;
 	auto pending_query = context->PendingQuery(rel, stream_result);
 	return DuckDBPyConnection::CompletePendingQuery(*pending_query);
@@ -791,6 +790,7 @@ unique_ptr<QueryResult> DuckDBPyRelation::ExecuteInternal(bool stream_result) {
 }
 
 void DuckDBPyRelation::ExecuteOrThrow(bool stream_result) {
+	py::gil_scoped_acquire gil;
 	result.reset();
 	auto query_result = ExecuteInternal(stream_result);
 	if (!query_result) {
@@ -1358,6 +1358,7 @@ unique_ptr<DuckDBPyRelation> DuckDBPyRelation::Query(const string &view_name, co
 		return Query(view_name, query);
 	}
 	{
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release release;
 		auto query_result = rel->context.GetContext()->Query(std::move(parser.statements[0]), false);
 		// Execute it anyways, for creation/altering statements
@@ -1394,6 +1395,7 @@ void DuckDBPyRelation::Insert(const py::object &params) {
 	}
 	vector<vector<Value>> values {DuckDBPyConnection::TransformPythonParamList(params)};
 
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release release;
 	rel->Insert(values);
 }
@@ -1500,6 +1502,7 @@ static void DisplayHTML(const string &html) {
 
 string DuckDBPyRelation::Explain(ExplainType type) {
 	AssertRelation();
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release release;
 
 	auto explain_format = GetExplainFormat(type);
diff --git a/tools/pythonpkg/src/pyresult.cpp b/tools/pythonpkg/src/pyresult.cpp
index b6ba40315b9e..13d741eff065 100644
--- a/tools/pythonpkg/src/pyresult.cpp
+++ b/tools/pythonpkg/src/pyresult.cpp
@@ -31,6 +31,7 @@ DuckDBPyResult::DuckDBPyResult(unique_ptr<QueryResult> result_p) : result(std::m
 
 DuckDBPyResult::~DuckDBPyResult() {
 	try {
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release gil;
 		result.reset();
 		current_chunk.reset();
@@ -109,6 +110,7 @@ unique_ptr<DataChunk> DuckDBPyResult::FetchNextRaw(QueryResult &query_result) {
 
 Optional<py::tuple> DuckDBPyResult::Fetchone() {
 	{
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release release;
 		if (!result) {
 			throw InvalidInputException("result closed");
@@ -246,6 +248,7 @@ py::dict DuckDBPyResult::FetchNumpyInternal(bool stream, idx_t vectors_per_chunk
 			}
 			unique_ptr<DataChunk> chunk;
 			{
+				D_ASSERT(py::gil_check());
 				py::gil_scoped_release release;
 				chunk = FetchNextRaw(stream_result);
 			}
@@ -339,6 +342,7 @@ bool DuckDBPyResult::FetchArrowChunk(ChunkScanState &scan_state, py::list &batch
 	idx_t count;
 	auto &query_result = *result.get();
 	{
+		D_ASSERT(py::gil_check());
 		py::gil_scoped_release release;
 		count = ArrowUtil::FetchChunk(scan_state, query_result.client_properties, rows_per_batch, &data);
 	}
diff --git a/tools/pythonpkg/src/python_udf.cpp b/tools/pythonpkg/src/python_udf.cpp
index 8cac9a0d0d4e..7667c3ba21e4 100644
--- a/tools/pythonpkg/src/python_udf.cpp
+++ b/tools/pythonpkg/src/python_udf.cpp
@@ -68,6 +68,7 @@ void AreExtensionsRegistered(const LogicalType &arrow_type, const LogicalType &d
 static void ConvertArrowTableToVector(const py::object &table, Vector &out, ClientContext &context, idx_t count) {
 	// Create the stream factory from the Table object
 	auto ptr = table.ptr();
+	D_ASSERT(py::gil_check());
 	py::gil_scoped_release gil;
 
 	auto stream_factory = make_uniq<PythonTableArrowArrayStreamFactory>(ptr, context.GetClientProperties());


Test patch:
diff --git a/tools/pythonpkg/tests/fast/arrow/test_polars.py b/tools/pythonpkg/tests/fast/arrow/test_polars.py
index d61cd11d7203..1238bd3ec10e 100644
--- a/tools/pythonpkg/tests/fast/arrow/test_polars.py
+++ b/tools/pythonpkg/tests/fast/arrow/test_polars.py
@@ -67,7 +67,9 @@ def test_polars_from_json(self, duckdb_cursor):
         res = duckdb_cursor.read_json(string).pl()
         assert str(res['entry'][0][0]) == "{'content': {'ManagedSystem': {'test': None}}}"
 
-    @pytest.mark.skipif(sys.version_info < (3, 8), reason="Polars PanicException is not supported in earlier versions")
+    @pytest.mark.skipif(
+        not hasattr(pl.exceptions, "PanicException"), reason="Polars has no PanicException in this version"
+    )
     def test_polars_from_json_error(self, duckdb_cursor):
         from io import StringIO