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
{{ message }}
Repository navigation
Enhance frame handing in warnings.warn() to skip by module rather that stacklevel #39615
This patch enhances warnings.warn() in the following
way: The stacklevel passed in may be negative. In that
case the call stack is searched for the innermost frame
whose module name differs in the first -stacklevel
components. This frame will be used in the report.
So when you have the following call stack:
m1.f()
m1.m11.f()
m1.m12.f()
m2.m21.f()
m2.m22.f()
and the innermost function() m2.m22.f() call
warnings.warn() with a stacklevel of -2 the frame
reported will be from m1.m12.f(), because it is the
first one from outside the m2 package.
I don't know how desireable this feature is, but
I think that a better solution would be to add
a new parameter to warnings.warn(), instead of
reusing the old one.
Also, your description is wrong; when warn() in
your example is called with stacklevel -2, the
reported frame is m2.m21.f(). To get your result,
you have to call warn() with stacklevel -1.
I think that a better solution would be to add
a skipmodules='moduleprefix' parameter to the
warn() function. warn() would then simply look
for the first frame whose module name doesn't
start with this prefix.
Here's an updated patch that implements your suggestion: skipmodules is a regular expression. Any module whose name matches the RE will be skipped when determining the stacklevel.
File Added: diff2.txt
zseil commented on Apr 15, 2007
zseilmannequin
Mannequin
More actions
Looks good to me. I like that skipmodules is a
regular expression, but I don't know how will it
affect the intended rewrite in C:
It would be nice if the documentation mentioned
what is the interaction between stacklevel and
skipmodules parameters, at least something like:
"If you want to issue a warning outside your module,
and you don't know how many frames will have to be
skipped for that, pass some big integer for stacklevel"
If this patch is accepted, it should be put to use in
the _struct module:
>>> struct.Struct("<l").pack(4023029188) # note: module is sys
sys:1: DeprecationWarning: struct integer overflow masking is deprecated
changed the title [-]Enhance frame handing in warnings.warn()[/-][+]Enhance frame handing in warnings.warn() to skip by module rather that stacklevel[/+]on Jan 1, 2023
Assigning to me to see if I get to this as I'm really wanting this feature while trying to add a warning deep within an an complicated package with multiple public API surfaces at different stacklevels.
It seems like "by fully qualified module name" is what code authors might want as that's how we think... But in practice that might be hard to implement in a reliable manner. The __file__ module or package prefix match effectively lets you do that. Anticipated common use path prefix matching use cases: skip_file_prefixes=(__file__,) or skip_file_prefixes=(os.path.dirname(__file__),)
Investigating... The code objects in the frame appears to have a .co_qualname attribute, but it that always set?
Code objects are always defined within a file thus co_filename should be set for anything coming from a .py source file in a module or package (C extensions or manual code object creation could supply whatever "filename" they want, but those unusual things aren't cases I'd worry about matching and skipping), but code objects are not required to have names or qualified names (lambdas, comprehension expressions, nested functions, etc)...
It might be possible to get the base module name itself via frame.f_globals['__name__'] but even that sounds unreliable, and using just the __name__ as a match to skip is pretty non-specific.
I'll poke around, but I'm not sure if it is possible.
The other constraint I've been keeping in this code: It must be a fast check. warn() should not do a lot of computation.
I don't believe module or package name is possible. Indeed frame.f_code.co_qualname doesn't give a module or package name. Frames and code objects don't have any reference back to a module or namespace. So I don't see any easy, fast, and reliable way to do that beyond the filename based match as my PR implements.
Activity
doerwalter commentedon Nov 27, 2003
This patch enhances warnings.warn() in the following
way: The stacklevel passed in may be negative. In that
case the call stack is searched for the innermost frame
whose module name differs in the first -stacklevel
components. This frame will be used in the report.
So when you have the following call stack:
m1.f()
m1.m11.f()
m1.m12.f()
m2.m21.f()
m2.m22.f()
and the innermost function() m2.m22.f() call
warnings.warn() with a stacklevel of -2 the frame
reported will be from m1.m12.f(), because it is the
first one from outside the m2 package.
zseil commentedon Apr 2, 2007
I don't know how desireable this feature is, but
I think that a better solution would be to add
a new parameter to warnings.warn(), instead of
reusing the old one.
Also, your description is wrong; when warn() in
your example is called with stacklevel -2, the
reported frame is m2.m21.f(). To get your result,
you have to call warn() with stacklevel -1.
I think that a better solution would be to add
a skipmodules='moduleprefix' parameter to the
warn() function. warn() would then simply look
for the first frame whose module name doesn't
start with this prefix.
doerwalter commentedon Apr 8, 2007
Here's an updated patch that implements your suggestion: skipmodules is a regular expression. Any module whose name matches the RE will be skipped when determining the stacklevel.
File Added: diff2.txt
zseil commentedon Apr 15, 2007
Looks good to me. I like that skipmodules is a
regular expression, but I don't know how will it
affect the intended rewrite in C:
http://www.python.org/sf/1631171
It would be nice if the documentation mentioned
what is the interaction between stacklevel and
skipmodules parameters, at least something like:
"If you want to issue a warning outside your module,
and you don't know how many frames will have to be
skipped for that, pass some big integer for stacklevel"
If this patch is accepted, it should be put to use in
the _struct module:
devdanzin commentedon Feb 14, 2009
Patch has tests, needs updating.
jayvdb commentedon Dec 10, 2015
See similar http://bugs.python.org/issue25216 aka #69403
[-]Enhance frame handing in warnings.warn()[/-][+]Enhance frame handing in warnings.warn() to skip by module rather that stacklevel[/+]gpshead commentedon Jan 1, 2023
Assigning to me to see if I get to this as I'm really wanting this feature while trying to add a warning deep within an an complicated package with multiple public API surfaces at different stacklevels.
pythongh-39615: Add warn() skip_file_prefixes= support.
merwok commentedon Jan 8, 2023
Skipping by module seems good, but the implementation relies on file names — could it be module or package name?
gpshead commentedon Jan 8, 2023
It seems like "by fully qualified module name" is what code authors might want as that's how we think... But in practice that might be hard to implement in a reliable manner. The
__file__module or package prefix match effectively lets you do that. Anticipated common use path prefix matching use cases:skip_file_prefixes=(__file__,)orskip_file_prefixes=(os.path.dirname(__file__),)Investigating... The code objects in the frame appears to have a
.co_qualnameattribute, but it that always set?Code objects are always defined within a file thus co_filename should be set for anything coming from a .py source file in a module or package (C extensions or manual code object creation could supply whatever "filename" they want, but those unusual things aren't cases I'd worry about matching and skipping), but code objects are not required to have names or qualified names (lambdas, comprehension expressions, nested functions, etc)...
It might be possible to get the base module name itself via
frame.f_globals['__name__']but even that sounds unreliable, and using just the__name__as a match to skip is pretty non-specific.I'll poke around, but I'm not sure if it is possible.
The other constraint I've been keeping in this code: It must be a fast check. warn() should not do a lot of computation.
gpshead commentedon Jan 12, 2023
I don't believe module or package name is possible. Indeed
frame.f_code.co_qualnamedoesn't give a module or package name. Frames and code objects don't have any reference back to a module or namespace. So I don't see any easy, fast, and reliable way to do that beyond the filename based match as my PR implements.gh-39615: Add warnings.warn() skip_file_prefixes support (#100840)
pythongh-39615: fix warning on return type mismatch
gh-39615: fix warning on return type mismatch (#101407)
pythongh-39615: Add warnings.warn() skip_file_prefixes support (pytho…
pythongh-39615: fix warning on return type mismatch (python#101407)
gpshead commentedon Feb 8, 2023
I'm calling this fixed as it can skip by filename now which was a performant way to implement this.