简体   繁体   English

Python 3单元测试中的ResourceWarning未关闭套接字

[英]ResourceWarning unclosed socket in Python 3 Unit Test

I'm modifying some code to be compatible between Python 2 and Python 3 , but have observed a warning in unit test output.我正在修改一些代码以在Python 2Python 3之间兼容,但在单元测试输出中观察到警告。

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py:601:
    ResourceWarning: unclosed socket.socket fd=4,
    family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6,
    laddr=('1.1.2.3', 65087), raddr=('5.8.13.21', 8080)

A little research determined this was also happening from popular libraries like requests and boto3 .一些研究确定这也发生在流行的库中,比如requestsboto3

I could ignore the warning or filter it completely.我可以忽略警告或完全过滤它 If was my service, I could set the connection: close header in my response ( link ).如果是我的服务,我可以在响应中设置connection: close标头( 链接)。

Here's an example that exhibits the warning in Python 3.6.1 :这是一个在Python 3.6.1中显示警告的示例:

app.py应用程序

import requests

class Service(object):
    def __init__(self):
        self.session = requests.Session()

    def get_info(self):
        uri = 'http://api.stackexchange.com/2.2/info?site=stackoverflow'
        response = self.session.get(uri)
        if response.status_code == 200:
            return response.json()
        else:
            response.raise_for_status()

    def __del__(self):
        self.session.close()

if __name__ == '__main__':
    service = Service()
    print(service.get_info())

test.py测试文件

import unittest

class TestService(unittest.TestCase):
    def test_growing(self):
        import app
        service = app.Service()
        res = service.get_info()
        self.assertTrue(res['items'][0]['new_active_users'] > 1)


if __name__ == '__main__':
    unittest.main()

Is there a better / correct way to manage the session so that it gets explicitly closed and not rely on __del__() to result in this sort of warning.是否有更好/正确的方法来管理会话,使其明确关闭而不依赖__del__()导致此类警告。

Thanks for any help.感谢您的帮助。

Having the teardown logic in __del__ can make your program incorrect or harder to reason about, because there is no guarantee on when that method will get called, potentially leading to the warning you got.__del__使用拆卸逻辑会使您的程序不正确或难以推理,因为无法保证何时调用该方法,可能会导致您收到警告。 There are a couple of ways to address this:有几种方法可以解决这个问题:

1) Expose a method to close the session, and call it in the test tearDown 1)公开一个关闭session的方法,在测试tearDown

unittest 's tearDown method allows you to define some code that will be run after each test. unittesttearDown方法允许您定义一些将在每次测试后运行的代码。 Using this hook to close the session will work even if the test fails or has an exception, which is nice.即使测试失败或有异常,使用这个钩子关闭会话也能工作,这很好。

app.py应用程序

import requests

class Service(object):

    def __init__(self):
        self.session = requests.Session()

    def get_info(self):
        uri = 'http://api.stackexchange.com/2.2/info?site=stackoverflow'
        response = self.session.get(uri)
        if response.status_code == 200:
            return response.json()
        else:
            response.raise_for_status()

    def close(self):
        self.session.close()

if __name__ == '__main__':
    service = Service()
    print(service.get_info())
    service.close()

test.py测试文件

import unittest
import app

class TestService(unittest.TestCase):

    def setUp(self):
        self.service = app.Service()
        super().setUp()

    def tearDown(self):
        self.service.close()

    def test_growing(self):
        res = self.service.get_info()
        self.assertTrue(res['items'][0]['new_active_users'] > 1)

if __name__ == '__main__':
    unittest.main()

2) Use a context manager 2)使用上下文管理器

A context manager is also a very useful way to explicitly define the scope of something. 上下文管理器也是一种非常有用的方式来明确定义某事物的范围。 In the previous example, you have to make sure .close() is called correctly at every call site, otherwise your resources will leak.在前面的示例中,您必须确保在每个调用站点正确调用.close() ,否则您的资源将泄漏。 With a context manager, this is handled automatically even if there is an exception within the scope of the context manager.使用上下文管理器,即使在上下文管理器的范围内存在异常,也会自动处理。

Building on top of solution 1), you can define extra magic methods ( __enter__ and __exit__ ) so that your class works with the with statement.在解决方案 1) 的基础上,您可以定义额外的魔术方法( __enter____exit__ ),以便您的类使用with语句。

Note: The nice thing here is that this code also supports the usage in solution 1), with explicit .close() , which can be useful if a context manager was inconvenient for some reason.注意:这里的好处是此代码还支持解决方案 1) 中的用法,带有显式.close() ,如果上下文管理器由于某种原因不方便,这可能很有用。

app.py应用程序

import requests

class Service(object):

    def __init__(self):
        self.session = requests.Session()

    def __enter__(self):
        return self

    def get_info(self):
        uri = 'http://api.stackexchange.com/2.2/info?site=stackoverflow'
        response = self.session.get(uri)
        if response.status_code == 200:
            return response.json()
        else:
            response.raise_for_status()

    def close(self):
        self.session.close()

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()

if __name__ == '__main__':
    with Service() as service:
        print(service.get_info())

test.py测试文件

import unittest

import app

class TestService(unittest.TestCase):

    def test_growing(self):
        with app.Service() as service:
            res = service.get_info()
        self.assertTrue(res['items'][0]['new_active_users'] > 1)

if __name__ == '__main__':
    unittest.main()

Depending on what you need, you can use either, or a combination of setUp / tearDown and context manager, and get rid of that warning, plus having more explicit resource management in your code!根据您的需要,您可以使用或组合使用setUp / tearDown和上下文管理器,并摆脱该警告,并在您的代码中进行更明确的资源管理!

This is the best solution if you are not much concern about warnings如果您不太关心警告,这是最好的解决方案

Just import warnings and add this line where your driver is initiating -只需导入警告并在您的驱动程序启动的地方添加这一行 -

import warnings

warnings.filterwarnings(action="ignore", message="unclosed", category=ResourceWarning)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 关于单元测试中 PySpark toPandas() 未关闭套接字的 ResourceWarning - ResourceWarning about unclosed socket from PySpark toPandas() in unit tests 在Python 3中使用urllib进行套接字资源警告 - socket ResourceWarning using urllib in Python 3 ResourceWarning:运行python selenium unittest时出现未关闭的文件错误 - ResourceWarning: unclosed file error while running python selenium unittest ResourceWarning:python-memcached没有关闭套接字? - ResourceWarning: python-memcached not closing socket? 未关闭但 UnitTest 正在抛出它的文件的 ResourceWarning - ResourceWarning for a file that is unclosed but UnitTest is throwing it Python3:Reportlab图像 - ResourceWarning:未闭合文件&lt;_io.BufferedReader name = ...&gt; - Python3: Reportlab Image - ResourceWarning: unclosed file <_io.BufferedReader name=…> "<i>Warning (from warnings module): ResourceWarning: unclosed<\/i>警告(来自警告模块):ResourceWarning:未关闭<\/b><socket.socket object, fd=404, family=2, type=1, proto=0><i>using selenium<\/i>使用硒<\/b>" - Warning (from warnings module): ResourceWarning: unclosed <socket.socket object, fd=404, family=2, type=1, proto=0> using selenium python IMAP4-SSL ResourceWarning:未关闭 - python IMAP4-SSL ResourceWarning: unclosed <ssl.SSLSocket fd=932, family=AddressFamily.AF_INET6, Python 3:ResourceWarning:unclosed文件<_io.TextIOWrapper name ='PATH_OF_FILE' - Python 3: ResourceWarning: unclosed file <_io.TextIOWrapper name='PATH_OF_FILE' 使 pytest 在资源警告(未关闭的文件)上失败 - Make pytest fail on ResourceWarning (unclosed files)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM