When returning a constant from a function or implicitly returning None, the return type is not captured in the trace:
def foo():
return 5
def bar():
print("hello")
$ monkeytype run foo_2.py
hello
$ sqlite3 monkeytype.sqlite3 "select * from monkeytype_call_traces where module = 'foo'"
2024-02-03 14:09:53.060108 foo foo {} NULL NULL
2024-02-03 14:09:53.060120 foo bar {} NULL NULL
I think the problem is that starting with Python 3.12, a new opcode RETURN_CONST is used in these cases. This fixes the problem for me:
diff --git a/monkeytype/tracing.py b/monkeytype/tracing.py
index e1e1eeb..a35497c 100644
--- a/monkeytype/tracing.py
+++ b/monkeytype/tracing.py
@@ -177,6 +177,7 @@ def get_func(frame: FrameType) -> Optional[Callable[..., Any]]:
RETURN_VALUE_OPCODE = opcode.opmap["RETURN_VALUE"]
+RETURN_CONST_OPCODE = opcode.opmap["RETURN_CONST"]
YIELD_VALUE_OPCODE = opcode.opmap["YIELD_VALUE"]
# A CodeFilter is a predicate that decides whether or not a the call for the
@@ -258,7 +259,7 @@ class CallTracer:
elif last_opcode == YIELD_VALUE_OPCODE:
trace.add_yield_type(typ)
else:
- if last_opcode == RETURN_VALUE_OPCODE:
+ if last_opcode in (RETURN_VALUE_OPCODE, RETURN_CONST_OPCODE):
trace.return_type = typ
del self.traces[frame]
self.logger.log(trace)
I haven't checked if this is the only case where new or changed opcodes break stuff, a lot of things have changed in recent Python versions.
When returning a constant from a function or implicitly returning
None
, the return type is not captured in the trace:I think the problem is that starting with Python 3.12, a new opcode
RETURN_CONST
is used in these cases. This fixes the problem for me:I haven't checked if this is the only case where new or changed opcodes break stuff, a lot of things have changed in recent Python versions.