gpt4 book ai didi

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

转载 作者:IT老高 更新时间:2023-10-28 21:05:04 26 4
gpt4 key购买 nike

我正在修改一些代码以在 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)

一项小研究确定,requests 等流行库中也发生了这种情况。和 boto3 .

我可以忽略警告或 filter it完全地。如果是我的服务,我可以在我的响应 (link) 中设置 connection: close header 。

这是一个在 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()

是否有更好/正确的方法来管理 session ,使其显式关闭而不依赖 __del__() 来产生这种警告。

感谢您的帮助。

最佳答案

__del__ 中包含拆卸逻辑可能会使您的程序不正确或难以推理,因为无法保证何时调用该方法,这可能会导致您收到警告。有几种方法可以解决这个问题:

1) 暴露一个关闭 session 的方法,在测试中调用tearDown

unittesttearDown方法允许您定义一些将在每次测试后运行的代码。即使测试失败或出现异常,使用此钩子(Hook)关闭 session 也可以工作,这很好。

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) 使用上下文管理器

一个 context manager也是显式定义某事物范围的一种非常有用的方法。在前面的示例中,您必须确保在每个调用站点都正确调用 .close(),否则您的资源将会泄漏。使用上下文管理器,即使上下文管理器范围内存在异常,也会自动处理。

在解决方案 1) 的基础上,您可以定义额外的魔法方法(__enter____exit__),以便您的类使用 with 声明。

注意:这里的好处是该代码还支持在解决方案 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()

根据您的需要,您可以使用 setUp/tearDown 和上下文管理器中的任何一个或组合使用,并摆脱该警告,并具有更明确的代码中的资源管理!

关于python - Python 3 单元测试中的 ResourceWarning 未关闭套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48160728/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com