50

Python 3.2 introduced ResourceWarning for unclosed system resources (network sockets, files):

Though the code runs clean in production, I am getting a lot of following warnings when running unit tests due to use of third party libraries where the warning occurs. I could fix the library, but on the other hand it were much simpler just to ignore it during the test run.

 block_io-python/block_io/__init__.py:182: ResourceWarning: unclosed <ssl.SSLSocket fd=11, family=AddressFamily.AF_INET, type=SocketType.SOCK_STREAM, proto=6, laddr=('x', 58395), raddr=('x, 443)>

What is the way to disable these warnings? I tried the following but no effect:

 warnings.filterwarnings("ignore", category=ResourceWarning)

(Run during unit test import time).

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
  • 3
    Maybe I am allowed if the obvious behavior does not work and I don't know what I am doing it wrong? :) – Mikko Ohtamaa Oct 25 '14 at 15:45
  • Could be that the module that is issuing the warning is using `warnings.showwarning`. The function seems to bypass the warning filter. – Dunes Oct 25 '14 at 20:26
  • Maybe the third party code also adds a `warnings.filterwarnings('default', category=ResourceWarning)`, which would override yours by being placed in front of it? And if @Dunes theory is right, you could overwrite `warnings.showwarning` within a Context Manager `with warnings.catch_warnings():` – greschd Oct 28 '14 at 21:47
  • @greschd: I'll test out the context manager to close out the possibility somebody else is tampering with the warnings. Thanks for the idea. – Mikko Ohtamaa Oct 28 '14 at 22:16
  • 1
    Line 3855 in http://fossies.org/dox/Python-3.4.2/socketmodule_8c_source.html is where the warning gets issued. All looks fine to me. Possibly issues are maybe the test harness is nixing the `__warningregistry__` of your module or that you are using python compiled in debug mode. Resource warnings are only shown by default when python is compiled in debug mode. Perhaps warnings cannot be hidden in debug mode... – Dunes Oct 29 '14 at 00:03

5 Answers5

56

I found the culprit. You say you set your filter during import time. However, since Python 3.2 the unittest module has been updated to set the warning filter to default. See Section 29.5.5. Basically, unittest overwrites your warning filter preferences after it has finished importing your modules.

For example.

my_tests.py

import socket
import unittest
import warnings

warnings.simplefilter("ignore", ResourceWarning)

def abusesocket():
    s = socket.socket()
    s.connect(("www.google.com", 80))

class Test(unittest.TestCase):

    def test1(self):
        print("test1")
        abusesocket()
        print("module import warning filter nixed")

    def test2(self):
        print("test2")
        warnings.simplefilter("ignore", ResourceWarning)
        abusesocket()
        print("higher warning filter okay")

Gives the following output

$ python3 -m unittest  my_tests.py 
test1
/home/user/my_tests.py:15: ResourceWarning: unclosed <socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketType.SOCK_STREAM, proto=0, laddr=('x.x.x.x', 52332), raddr=('31.55.166.217', 80)>
  abusesocket()
module import warning filter nixed
.test2
higher warning filter okay
.
----------------------------------------------------------------------
Ran 2 tests in 0.347s

OK

Solution

unittest appears to reset the warning filter after each test. So you'll have clear the filter at the start of each test. Probably best to use a decorator to wrap your test functions.

def ignore_warnings(test_func):
    def do_test(self, *args, **kwargs):
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", ResourceWarning)
            test_func(self, *args, **kwargs)
    return do_test

class Test(unittest.TestCase):

    @ignore_warnings
    def test1(self):
        abusesocket()
Dunes
  • 37,291
  • 7
  • 81
  • 97
30

unittest.main(warnings='ignore')

deepelement
  • 2,457
  • 1
  • 25
  • 25
13

This alternative worked for me:

    def setUp(self):
        if not sys.warnoptions:
            import warnings
            warnings.simplefilter("ignore")

See: Standard Library docs - Overriding the default filter

drond
  • 435
  • 3
  • 8
8

I used this to disable only the ResourceWarning warning before a test and re-enable it afterwards.


import unittest
import warnings

class MyTestCase(unittest.TestCase):

    def setUp(self):
        warnings.simplefilter("ignore", ResourceWarning)

    def tearDown(self):
        warnings.simplefilter("default", ResourceWarning)

Also see: Different options besides "default" and "ignore"

vlz
  • 911
  • 1
  • 10
  • 18
3

Setting it once for all methods at the class level seems more efficient than repeatedly as an instance-level setUp():

    @classmethod
    def setUpClass(cls):
        warnings.simplefilter("ignore")
Mark Sawers
  • 121
  • 2
  • 8