Skip to content
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

pytest doesn't display ResourceWarnings that unittest does #5676

Closed
mraspberry opened this issue Jul 30, 2019 · 11 comments
Closed

pytest doesn't display ResourceWarnings that unittest does #5676

mraspberry opened this issue Jul 30, 2019 · 11 comments
Labels
plugin: warnings related to the warnings builtin plugin type: bug problem that needs to be addressed

Comments

@mraspberry
Copy link

pytest doesn't seem to be displaying ResourceWarnings that unittest does display.
I'm using pytest 5.0.1 on python 3.6.8 on Ubuntu 18.04.2 LTS running in WSL on Windows 10.

Function being tested that triggers ResourceWarning in unittest but not pytest:

def trigger_resourcewarning(filename):
    return open(filename).read()

pytest test code:

import test_module

def test_module_trigger_resource_warning(tmp_path):
    contents = 'TEST\n'
    filename = tmp_path / 'test.txt'
    filename.write_text(contents)
    assert test_module.trigger_resourcewarning(filename) == contents

unittest test code:

import os
import tempfile
import unittest
import test_module

class TestModuleTriggerResourceWarning(unittest.TestCase):

    def test_module_trigger_resource_warning(self):
        contents = 'TEST\n'
        with tempfile.NamedTemporaryFile(delete=False) as fd:
            filename = fd.name
            fd.write(contents.encode())
        self.addCleanup(os.unlink, filename)
        self.assertEqual(test_module.trigger_resourcewarning(filename), contents)

pytest output:

platform linux -- Python 3.6.8, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /home/matt/projects/pytest-issue
collected 1 item

tests/test_resource_warning_proof.py .                                   [100%]

unittest output:

/home/matt/projects/pytest-issue/test_module/__init__.py:4: ResourceWarning: unclosed file <_io.TextIOWrapper name='/tmp/tmp1qw9u_dn' mode='r' encoding='UTF-8'>
  return open(filename).read()
.
----------------------------------------------------------------------
Ran 1 test in 0.006s

OK
@RonnyPfannschmidt
Copy link
Member

Pathlib closes the fd on the method used in the domonstratiob

@RonnyPfannschmidt
Copy link
Member

Oh wait, I did miss tread, please check if it happens with disabled assertion rewriting

@mraspberry
Copy link
Author

Seems to have the same behavior

$ pytest --assert=plain
============================= test session starts ==============================
platform linux -- Python 3.6.8, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /home/matt/projects/pytest-issue
collected 1 item

tests/test_resource_warning_proof.py .                                   [100%]

=========================== 1 passed in 0.05 seconds ===========================

@asottile
Copy link
Member

interesting:

def test():
    open(__file__).read()


if __name__ == '__main__':
    exit(test())
$ python3 -Wonce t.py
t.py:2: ResourceWarning: unclosed file <_io.TextIOWrapper name='t.py' mode='r' encoding='UTF-8'>
  open(__file__).read()
$ pytest -qq t.py
.                                                                        [100%]
$ pytest -Wonce -qq t.py
.                                                                        [100%]
=============================== warnings summary ===============================
t.py::test
  /tmp/x/t.py:2: ResourceWarning: unclosed file <_io.TextIOWrapper name='/tmp/x/t.py' mode='r' encoding='UTF-8'>
    open(__file__).read()

-- Docs: https://docs.pytest.org/en/latest/warnings.html
$ pytest -Werror -qq t.py
.                            

@asottile asottile added plugin: warnings related to the warnings builtin plugin type: bug problem that needs to be addressed labels Jul 31, 2019
@nicoddemus
Copy link
Member

nicoddemus commented Jul 31, 2019

We register/unregister handlers at various stages, such as test setup/call/teardown, collection, etc. I think the last hook called where we still capture warnings is pytest_terminal_summary:

@pytest.hookimpl(hookwrapper=True)
def pytest_terminal_summary(terminalreporter):
config = terminalreporter.config
with catch_warnings_for_item(
config=config, ihook=config.hook, when="config", item=None
):
yield

What I want to say is that we are not capturing warnings during the entire session, but only at some points.

I wonder if we could start warning capture during pytest_configure and end during pytest_unconfigure... 🤔

@asottile
Copy link
Member

I'm more surprised that when I elevate it to -Werror that it is nowhere to be seen 🤔

@mraspberry
Copy link
Author

I'd like to take a stab at fixing this. How should I go about that?

@nicoddemus
Copy link
Member

nicoddemus commented Aug 3, 2019

I think I would follow these steps:

  1. Try to pinpont at which point exactly the warning is happening. I would start with -Werror, but as @asottile demonstrates that is not reliable as we expected.
  2. After that, we should find the adequate pytest hook to implement and catch warnings around it.

I've investigated a bit the pytest_configure approach I mentioned in #5676 (comment), but it is not that simple, because we can't reuse catch_warnings, we would need to implement what catch_warnings does manually (and in fact it is what pytest itself used to do), because we need more fine grained control of what happens when a warning is issued, not just log it away for future use.

@asottile
Copy link
Member

there's a hint in #8021 -- pytest should probably implement sys.unraisablehook for py3.8+ to help with this

@dstansby
Copy link

This Stack Overflow post might provide some clues:

Unfortunately, it doesn't appear to be possible. That "Exception ignored in:" message is produced by the CPython function PyErr_WriteUnraisable in Python/errors.c. The comment before that function states:

/* Call when an exception has occurred but there is no way for Python
to handle it. Examples: exception in del or during GC. */

The ResourceWarning is indeed being generated during garbage collection, and Python prints a message because it doesn't have a way to raise an exception at that point. This has to do with the core CPython implementation and there is nothing that unittest can do to override it.

@The-Compiler
Copy link
Member

Indeed setting sys.unraisablehook helps here - closing this as duplicate of #5299 which will be fixed via #8055 soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plugin: warnings related to the warnings builtin plugin type: bug problem that needs to be addressed
Projects
None yet
Development

No branches or pull requests

6 participants