You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
### Work Item / Issue Reference
<!--
IMPORTANT: Please follow the PR template guidelines below.
For mssql-python maintainers: Insert your ADO Work Item ID below (e.g.
AB#37452)
For external contributors: Insert Github Issue number below (e.g. #149)
Only one reference is required - either GitHub issue OR ADO Work Item.
-->
<!-- mssql-python maintainers: ADO Work Item -->
>
[AB#39063](https://sqlclientdrivers.visualstudio.com/c6d89619-62de-46a0-8b46-70b92a84d85e/_workitems/edit/39063)
-------------------------------------------------------------------
### Summary
<!-- Insert your summary of changes below. Minimum 10 characters
required. -->
## Problem
Pytest test suite (335+ tests) was crashing on exit with:
```
Fatal Python error: _Py_GetConfig: the function must be called with the GIL held,
after Python initialization and before Python finalization, but the GIL is released
```
The crash occurred **after all tests passed**, during Python shutdown on
Windows x64 and macOS.
## Root Cause
Static `pybind11::module_` and `pybind11::object` instances in
`BindParameterArray()` function (lines 2072-2073) were being destroyed
during C++ static destruction phase, which happens **after** Python has
released the GIL and begun finalization.
When the destructors called `Py_XDECREF`, Python's `_Py_GetConfig()` was
invoked without the GIL, causing the fatal error.
```cpp
// OLD CODE - Problematic static objects
static py::module_ uuid_mod = py::module_::import("uuid");
static py::object uuid_class = uuid_mod.attr("UUID");
```
## Solution
Moved UUID class caching to module initialization level using a helper
function. This ensures the Python object lifecycle is managed within
pybind11's module context, avoiding destructor calls during
finalization.
```cpp
// NEW CODE - Module-level cached helper
py::object uuid_class = py::module_::import("mssql_python.ddbc_bindings").attr("_get_uuid_class")();
```
The `_get_uuid_class()` helper is defined at module initialization and
maintains a static cache that lives for the module's lifetime, properly
integrated with pybind11's lifecycle management.
## Testing
- ✅ Full test suite (335+ tests) now completes without crash on macOS
- ✅ Exit code 0 after pytest completion
- ✅ No functionality changes - UUID parameter binding works identically
## Impact
- **Platforms affected**: Windows x64, macOS (all platforms with the
issue)
- **Risk**: Low - surgical fix, no behavioral changes
- **Files changed**: 1 file, ~15 lines added/modified
0 commit comments