Skip to content

bpo-29731: Allow warnings filter to print current stack. #498

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

Closed
wants to merge 3 commits into from

Conversation

Carreau
Copy link
Contributor

@Carreau Carreau commented Mar 6, 2017

It is similar to "always" but show the full stack of where the warning
was triggered.

Currently incomplete, does not respect the stacklevel= value, and
non-tested. Code may be shared with the traceback module as well, but
may need a tiny bit of refactoring, stack is printed backward.

~/dev/cpython stack $ cat foo.py
import warnings
warnings.filterwarnings('stack')

def foo():
    warnings.warn('this', UserWarning)

def bar():
    foo()

bar()
~/dev/cpython stack $ ./python.exe foo.py
  File "foo.py", line 5, in foo
    warnings.warn('this', UserWarning)
  File "foo.py", line 8, in bar
    foo()
  File "foo.py", line 10, in <module>
    bar()
foo.py:5: UserWarning: this
  warnings.warn('this', UserWarning)

https://bugs.python.org/issue29731

@mention-bot
Copy link

@Carreau, thanks for your PR! By analyzing the history of the files in this pull request, we identified @tiran, @brettcannon, @Haypo, @benjaminp and @loewis to be potential reviewers.

@serhiy-storchaka serhiy-storchaka added the type-feature A feature request or enhancement label Dec 8, 2018
@csabella csabella requested a review from vstinner May 28, 2019 23:37
@csabella
Copy link
Contributor

Closing and re-opening to rerun CI.

@csabella csabella closed this May 28, 2019
@csabella csabella reopened this May 28, 2019
@@ -440,6 +479,7 @@ warn_explicit(PyObject *category, PyObject *message,
PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
PyObject *item = NULL;
PyObject *action;
PyFrameObject *f = PyThreadState_GET()->frame;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move it into the print_frames() block, it's only needed there. Or even move it into print_frames() function.

You should use _PyThreadState_GET() to ensure that you get the optimized macro ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My C is rusty, so apologies for potentially simple questions:
isn't that the same because pycore_pystate aliases it ?

Include/internal/pycore_pystate.h:#define PyThreadState_GET() _PyThreadState_GET()

Also Im' confused about the uppercase vs lowercase PyThreadState(_Get/_GET).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only get the alias if you include pycore_pystate. I prefer to always use _PyThreadState_GET() to ensure to always get the optimized macro.



static void
print_frames(PyFrameObject *frame)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to rename it to print_stack() to be more consistent with the traceback module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also printing correctly in C and having the exact same behavior in warnigns.py and warning.c seem a hassle, can I go the PyImport route and do the equivalent of

f = sys._getframe().f_back.f_back
traceback.print_stack(f=f)

I know that warning.c is meant to be efficient but here it's an opt-in path, so maybe not that necessary to be completely in C ?

tb_displayline(
f_stderr,
frame->f_code->co_filename,
PyCode_Addr2Line(frame->f_code, frame->f_lasti),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyFrame_GetLineNumber() must be used here.

nitpick: I would prefer to compute it before calling tb_displayline():

int lineno = PyFrame_GetLineNumber(frame);
tb_displayline(...);

Py_DECREF(line);
if (err != 0)
return err;
/* ignore errors since we can't report them, can we? */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to remove the comment.

We could report the error, but I don't think that it's worth it. It would be annoying that logging a warning would emit a second warning/exception.


if (filename == NULL || name == NULL)
return -1;
line = PyUnicode_FromFormat(" File \"%U\", line %d, in %U\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PyUnicode_FromFormat("%U", arg) doesn't check if arg is really a Unicode type.

I suggest to use %S instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I completely forgot I had this PR opened, I'll have to get get back into what I was thinking.

It's interesting because I just copy and pasted this from traceback.c, so I guess these comments will apply there as well; and I should likely use the tb_displayline from traceback.c right ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, you must also fix traceback.c.

Carreau and others added 3 commits May 29, 2019 10:41
It is similar to "always" but show the full stack of where the warning
was triggered.

Currently incomplete, does not respect the `stacklevel=` value, and
non-tested. Code may be shared with the traceback module as well, but
may need a tiny bit of refactoring, stack is printed backward.

    ~/dev/cpython stack $ cat foo.py
    import warnings
    warnings.filterwarnings('stack')

    def foo():
        warnings.warn('this', UserWarning)

    def bar():
        foo()

    bar()
    ~/dev/cpython stack $ ./python.exe foo.py
      File "foo.py", line 5, in foo
        warnings.warn('this', UserWarning)
      File "foo.py", line 8, in bar
        foo()
      File "foo.py", line 10, in <module>
        bar()
    foo.py:5: UserWarning: this
      warnings.warn('this', UserWarning)
@vstinner
Copy link
Member

vstinner commented Jun 4, 2019

@serhiy-storchaka: This idea is interesting. Would you mind to have a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting review type-feature A feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants