Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ As of build 305, installation .exe files have been deprecated; see
Coming in build 312, as yet unreleased
--------------------------------------

* Fixed `axdebug` using Python 3.11+ new opaque frame APIs. Also fixed wrong step-over behavior (adb.py, not stepping after func returns when debugging active python script) (wxinix-2022#2723)
* Removed more leftover obsolete `UNICODE` constants since dropping Python 2 support in `win32ui`, `win32gui` and `win32clipboard` (mhammond#2717, [@Avasam][Avasam])
* Implement COM Records as [out] method parameters (mhammond#2708, [@geppi][geppi], [@the-snork][the-snork])
* Implement multidimensional SAFEARRAY(COM Record) and SAFEARRAY(double) (mhammond#2655, [@geppi][geppi])
Expand Down
10 changes: 5 additions & 5 deletions com/win32comext/axdebug/adb.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,8 @@ def __xxxxx__set_break(self, filename, lineno, cond=None):

def stop_here(self, frame):
traceenter("stop_here", _dumpf(frame), _dumpf(self.stopframe))
# As per bdb.stop_here, except for logicalbotframe
# if self.stopframe is None:
# return 1
if frame is self.stopframe:
return 1

tracev("stop_here said 'No'!")
return 0

Expand Down Expand Up @@ -146,7 +142,11 @@ def dispatch_return(self, frame, arg):
tracev("dispatch_return resetting sys.trace")
sys.settrace(None)
return
# self.bSetTrace = 0
# When stepping over (set_next), stopframe is the current function's
# frame. When that function returns, promote stopframe to the caller
# so dispatch_line stops at the next line in the caller.
if self.stopframe is frame and frame.f_back is not None:
self.stopframe = frame.f_back
self.currentframe = frame.f_back
return bdb.Bdb.dispatch_return(self, frame, arg)

Expand Down
39 changes: 30 additions & 9 deletions com/win32comext/axdebug/src/AXDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ generates Windows .hlp files.
#include "PyIEnumDebugPropertyInfo.h"

// Headers needed for the f_trace hacks.
#if PY_VERSION_HEX < 0x030b0000 // < 3.11
#include "compile.h"
#include "frameobject.h"
#endif

static PyObject *axdebug_Error; /* 'Python level' errors */

Expand Down Expand Up @@ -171,6 +173,7 @@ static PyObject *GetThreadStateHandle(PyObject *self, PyObject *args)
PyThreadState_Swap(myState);
return PyWinLong_FromVoidPtr(myState);
}
// clang-format off
static PyObject *SetThreadStateTrace(PyObject *self, PyObject *args)
{
PyObject *obhandle;
Expand All @@ -180,16 +183,33 @@ static PyObject *SetThreadStateTrace(PyObject *self, PyObject *args)
PyThreadState *state;
if (!PyWinLong_AsVoidPtr(obhandle, (void **)&state))
return NULL;
#pragma message("XXXXXXXXX - upgrade this for new tracing features.")
/***
// XXX - This was the code for Python<2.3: maybe use PyEval_SetTrace ????
Py_XDECREF(state->c_tracefunc);
state->c_tracefunc = func;
state->tracing = TRUE;
***/

// Loop back over all frames, setting each frame back to our
// first script block frame with the tracer.
#if PY_VERSION_HEX >= 0x030b0000 // >= 3.11: PyFrameObject is opaque
PyFrameObject *frame = state ? PyThreadState_GetFrame(state) : NULL;
bool bFoundFirstScriptBlock = false;
while (frame) {
PyCodeObject *code = PyFrame_GetCode(frame);
PyObject *filename = PyObject_GetAttrString((PyObject *)code, "co_filename");
Py_DECREF(code);
const char *filename_str = filename ? PyUnicode_AsUTF8(filename) : NULL;
bool isScriptBlock = filename_str && strncmp(filename_str, "<Script ", 8) == 0;
Py_XDECREF(filename);
if (isScriptBlock)
bFoundFirstScriptBlock = true;
else {
if (bFoundFirstScriptBlock) {
Py_DECREF(frame);
break;
}
}
PyObject_SetAttrString((PyObject *)frame, "f_trace", func);
PyFrameObject *prev_frame = frame;
frame = PyFrame_GetBack(frame);
Py_DECREF(prev_frame);
}
#else // < 3.11: direct struct access
PyFrameObject *frame = state ? state->frame : NULL;
bool bFoundFirstScriptBlock = false;
while (frame) {
Expand All @@ -204,9 +224,10 @@ static PyObject *SetThreadStateTrace(PyObject *self, PyObject *args)
Py_INCREF(func);
frame = frame->f_back;
}
Py_INCREF(Py_None);
return Py_None;
#endif
Py_RETURN_NONE;
}
// clang-format on
/* List of module functions */
// @module axdebug|A module, encapsulating the ActiveX Debugging interfaces
static struct PyMethodDef axdebug_methods[] = {{"GetStackAddress", GetStackAddress, 1},
Expand Down
6 changes: 0 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,12 +383,6 @@ def finalize_options(self) -> None:

def _why_cant_build_extension(self, ext):
"""Return None, or a reason it can't be built."""
# axdebug fails to build on 3.11 due to Python "frame" objects changing.
# This could be fixed, but is almost certainly not in use any more, so
# just skip it.
if ext.name == "axdebug" and sys.version_info >= (3, 11):
return "AXDebug no longer builds on 3.11 and up"

include_dirs = self.compiler.include_dirs + os.environ.get("INCLUDE", "").split(
os.pathsep
)
Expand Down
Loading