-
-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
isinstance return different result with sys.setprofile #318
Comments
FWIW, I can reproduce this with Python 3.8.18 and 3.9.18, but not with 3.10.13 and 3.11.6, where the typing version of ParamSpec is re-exported. |
After some investigation at the PyCon sprints, we determined that this is caused by a CPython bug where The bug only exists on Python <=3.10. It can be demonstrated in the following reproducible example. We can see that instances of Minimal repro: import sys
class TypeVar: pass
class GlobalParamSpec:
__class__ = TypeVar
def m(self):
__class__
def run():
class LocalParamSpec:
__class__ = TypeVar
def m(self):
__class__
print(
"Global class: ",
isinstance(GlobalParamSpec(), TypeVar),
GlobalParamSpec.__dict__.get('__class__'),
"Local class: ",
isinstance(LocalParamSpec(), TypeVar),
LocalParamSpec.__dict__.get('__class__'),
)
def trace_call(frame, event, arg):
# print(frame, event, arg)
return trace_call
if __name__ == "__main__":
print('Without profiling function')
run()
print()
sys.setprofile(trace_call)
print('With profiling function')
run()
print()
sys.setprofile(None)
print('Without profiling function again')
run() Output of the script, on Python 3.8, 3.9 and 3.10:
Thanks to @brandtbucher and @carljm for helping debug this! |
I bisected which commit during Python 3.11 development fixed the CPython bug (git bisect says the "first bad commit", but it's really the "first good commit"):
|
python/cpython@d7163bb didn't really fix the underlying CPython bug. It actually just made import sys
class A: pass
class GlobalB:
__class__ = A
def m(self):
__class__
def run():
class LocalB:
__class__ = A
def m(self):
__class__
print(
"Global class: ",
isinstance(GlobalB(), A),
GlobalB.__dict__.get('__class__'),
"Local class: ",
isinstance(LocalB(), A),
LocalB.__dict__.get('__class__'),
)
def trace_call(frame, event, arg):
frame.f_locals
return trace_call
if __name__ == "__main__":
print('Without profiling function')
run()
print()
sys.setprofile(trace_call)
print('With profiling function')
run()
print()
sys.setprofile(None)
print('Without profiling function again')
run() The bug does not reproduce on 3.13.0b1 or the CPython |
python: 3.8.5
The text was updated successfully, but these errors were encountered: