Skip to content

Instantly share code, notes, and snippets.

@sethmlarson
Last active February 11, 2022 14:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sethmlarson/dba167c50ef1f441dfb9e5dbf033efb8 to your computer and use it in GitHub Desktop.
Save sethmlarson/dba167c50ef1f441dfb9e5dbf033efb8 to your computer and use it in GitHub Desktop.
Dynamically determine stacklevel for use with warnings.warn(..., stacklevel=X)
import inspect
import sys
from pathlib import Path
def warn_stacklevel() -> int:
"""Dynamically determine stacklevel for warnings based on the call stack"""
try:
# Grab the root module from the current module '__name__'
module_name = __name__.partition(".")[0]
module_path = Path(sys.modules[module_name].__file__)
# If the module is a folder we're looking at
# subdirectories, otherwise we're looking for
# an exact match.
module_is_folder = module_path.name == "__init__.py"
if module_is_folder:
module_path = module_path.parent
# Look through frames until we find a file that
# isn't a part of our module, then return that stacklevel.
for level, frame in enumerate(inspect.stack()):
# Garbage collecting frames
frame_filename = Path(frame.filename)
del frame
if (
# If the module is a folder we look at subdirectory
module_is_folder
and module_path not in frame_filename.parents
) or (
# Otherwise we're looking for an exact match.
not module_is_folder
and module_path != frame_filename
):
return level
except KeyError:
pass
return 0
# Use like so:
import warnings
warnings.warn("This is a warning!", stacklevel=warn_stacklevel())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment