Pillow+numpy+unittest 给出 ResourceWarning: does this indicate a leak?
Pillow+numpy+unittest gives a ResourceWarning: does this indicate a leak?
当我在 Python3 上使用 Pillow(3.3.0 版,通过 pip 安装)将图像数据加载到 numpy 数组中时,我的单元测试报告 ResourceWarning
。例如,当我 运行 以下脚本时会出现警告:
#! /usr/bin/env python3
import unittest
import numpy as np
import PIL.Image
def load_image():
with PIL.Image.open('test.tif') as im:
return np.array(im)
class TestData(unittest.TestCase):
def test_PIL(self):
im = load_image()
print(im.shape)
unittest.main()
输出为
./err.py:14: ResourceWarning: unclosed file <_io.BufferedReader name='test.tif'>
im = load_image()
(420, 580)
.
----------------------------------------------------------------------
Ran 1 test in 0.012s
OK
(如果我不将图像包装在 numpy 数组中,警告就会消失。)
此资源警告是否表明我的代码中存在泄漏(例如,除了使用 with
语句之外,我是否需要以某种方式 "close" 图像文件)?或者,如果警告是虚假的,我该如何禁用它?
TL;DR,我认为这是一个错误。这应该会按预期关闭文件句柄:
def load_image():
with open('test.tif', 'rb') as im_handle:
im = PIL.Image.open(im_handle)
return np.array(im)
好的,让我们看看实际发生了什么:
为此我们添加了一个记录器:
#! /usr/bin/env python3
import logging
logging.getLogger().setLevel(logging.DEBUG)
logging.debug('hi from the logger!')
import unittest
import numpy as np
import PIL.Image
def load_image():
with PIL.Image.open('test.tif') as im:
return np.array(im)
class TestData(unittest.TestCase):
def test_PIL(self):
im = load_image()
print(im.shape)
unittest.main()
这是我们得到的:
DEBUG:root:hi from the logger!
/Users/ch/miniconda/envs/sci34/lib/python3.4/site-packages/PIL/Image.py:678: ResourceWarning: unclosed file <_io.BufferedReader name='test.tif'>
self.load()
DEBUG:PIL.Image:Error closing: 'NoneType' object has no attribute 'close'
(225, 300, 3)
.
----------------------------------------------------------------------
Ran 1 test in 0.022s
OK
DEBUG:PIL.Image:Error closing: 'NoneType' object has no attribute 'close'
在 Image
class:
的关闭方法中引发
def close(self):
"""
Closes the file pointer, if possible.
This operation will destroy the image core and release its memory.
The image data will be unusable afterward.
This function is only required to close images that have not
had their file read and closed by the
:py:meth:`~PIL.Image.Image.load` method.
"""
try:
self.fp.close()
except Exception as msg:
logger.debug("Error closing: %s", msg)
# Instead of simply setting to None, we're setting up a
# deferred error that will better explain that the core image
# object is gone.
self.im = deferred_error(ValueError("Operation on closed image"))
换句话说:
在with
块的末尾,调用了close
方法。它尝试关闭存储在 self.fp
中的打开文件句柄。但是在您的情况下 self.fp
不是文件句柄,因此无法关闭。关闭失败无提示。
所以当你离开with
块时,文件句柄没有关闭,nose的错误信息是合法的。
当我在 Python3 上使用 Pillow(3.3.0 版,通过 pip 安装)将图像数据加载到 numpy 数组中时,我的单元测试报告 ResourceWarning
。例如,当我 运行 以下脚本时会出现警告:
#! /usr/bin/env python3
import unittest
import numpy as np
import PIL.Image
def load_image():
with PIL.Image.open('test.tif') as im:
return np.array(im)
class TestData(unittest.TestCase):
def test_PIL(self):
im = load_image()
print(im.shape)
unittest.main()
输出为
./err.py:14: ResourceWarning: unclosed file <_io.BufferedReader name='test.tif'>
im = load_image()
(420, 580)
.
----------------------------------------------------------------------
Ran 1 test in 0.012s
OK
(如果我不将图像包装在 numpy 数组中,警告就会消失。)
此资源警告是否表明我的代码中存在泄漏(例如,除了使用 with
语句之外,我是否需要以某种方式 "close" 图像文件)?或者,如果警告是虚假的,我该如何禁用它?
TL;DR,我认为这是一个错误。这应该会按预期关闭文件句柄:
def load_image():
with open('test.tif', 'rb') as im_handle:
im = PIL.Image.open(im_handle)
return np.array(im)
好的,让我们看看实际发生了什么:
为此我们添加了一个记录器:
#! /usr/bin/env python3
import logging
logging.getLogger().setLevel(logging.DEBUG)
logging.debug('hi from the logger!')
import unittest
import numpy as np
import PIL.Image
def load_image():
with PIL.Image.open('test.tif') as im:
return np.array(im)
class TestData(unittest.TestCase):
def test_PIL(self):
im = load_image()
print(im.shape)
unittest.main()
这是我们得到的:
DEBUG:root:hi from the logger!
/Users/ch/miniconda/envs/sci34/lib/python3.4/site-packages/PIL/Image.py:678: ResourceWarning: unclosed file <_io.BufferedReader name='test.tif'>
self.load()
DEBUG:PIL.Image:Error closing: 'NoneType' object has no attribute 'close'
(225, 300, 3)
.
----------------------------------------------------------------------
Ran 1 test in 0.022s
OK
DEBUG:PIL.Image:Error closing: 'NoneType' object has no attribute 'close'
在 Image
class:
def close(self):
"""
Closes the file pointer, if possible.
This operation will destroy the image core and release its memory.
The image data will be unusable afterward.
This function is only required to close images that have not
had their file read and closed by the
:py:meth:`~PIL.Image.Image.load` method.
"""
try:
self.fp.close()
except Exception as msg:
logger.debug("Error closing: %s", msg)
# Instead of simply setting to None, we're setting up a
# deferred error that will better explain that the core image
# object is gone.
self.im = deferred_error(ValueError("Operation on closed image"))
换句话说:
在with
块的末尾,调用了close
方法。它尝试关闭存储在 self.fp
中的打开文件句柄。但是在您的情况下 self.fp
不是文件句柄,因此无法关闭。关闭失败无提示。
所以当你离开with
块时,文件句柄没有关闭,nose的错误信息是合法的。