importlib_resources 向后移植与 pyfakefs 不兼容?
importlib_resources backport not compatible with pyfakefs?
我正在重构一个库以将 importlib.resources 用于 python 3.7+。我正在使用 importlib_resources 向后移植来实现 python 3.6 兼容性。该代码适用于 pythons 3.6-3.8。但是,使用 pyfakefs 的 pytest 测试在 3.6 中失败。在测试条件下,使用 importlib_resources 的路径 return 被破坏(但在 "real-world" 条件下它们 return 正确)。
一个最小的例子:我有以下库结构:
mypackage
├── mypackage
│ ├── __init__.py
│ ├── bin
│ │ └── __init__.py
│ └── find_bin.py
└── tests
└── test_find_bin.py
在实际的库中,bin 文件夹包含二进制文件(加上一个空 __init__
)。库中其他地方的代码需要一个路径。 find_bin.py
演示了一个将 return 路径的函数:
import sys
if sys.version_info >= (3, 7):
from importlib import resources
else:
import importlib_resources as resources
import mypackage.bin
def find_bin():
init_path_context = resources.path(mypackage.bin, '__init__.py')
with init_path_context as p:
init_path = p
bin_path = init_path.parent
return bin_path
pytest测试test_find_bin.py
:
import pathlib
from mypackage.find_bin import find_bin
def test_findbin(fs):
test_bin = (pathlib.Path(__file__)
.resolve()
.parent.parent
.joinpath('mypackage', 'bin'))
print('test bin is ', test_bin)
expected_bin = find_bin()
print('expected bin is ', expected_bin)
assert not expected_bin.exists()
print('test creating fakefs ', test_bin)
fs.create_dir(test_bin)
assert expected_bin.exists()
Python 3.7+ 在测试中按预期工作。在 python 3.6 中,expected_bin 路径被破坏:
test bin is /Users/geoffreysametz/Documents/mypackage/mypackage/bin # correct
expected bin is /var/folders/bv/m5cg5cp15t38sh8rxx244hp00000gn/T # ?!?!?!
我试图跟踪 find_bin 函数的执行过程,它又长又复杂。但是,我看到 importlib_resources
使用了 python 的 FakeFilesystem class。我的假设是问题是由 importlib_resources
和 pytest 同时使用假文件系统引起的。
我的假设是否正确?是否有解决方法让 pytest 测试使用 importlib_resources 的代码?
pyfakefs 中的假文件系统在测试开始时是空的(除了 tempfile
模块所需的临时文件路径),所以如果你想访问 real 文件系统在你的测试中,你必须 map them into the fake filesystem:
def test_findbin(fs):
test_bin = (pathlib.Path(__file__)
.resolve()
.parent.parent
.joinpath('mypackage', 'bin'))
fs.add_real_directory(test_bin)
...
在你的真实测试中,你事先不知道路径,所以你必须添加一些你知道的父路径来包含你的资源。子目录和文件将在访问时被读取并复制到假文件系统。
关于您在 Python 3.6 中的测试行为:contextlib_package
中的代码首先检查(正确的)路径是否存在,如果不存在(因为它检查假的文件系统,它不会存在),它会创建一个临时文件,它试图在其中复制一些数据 - 因此是输出中的临时路径。
在Python 3.8中,似乎不检查路径是否存在,它只是从正确的路径创建一个Path
对象。当您尝试访问该路径中的某些资源时,这无论如何都会失败,因为它们不存在于假文件系统中,因此在这种情况下您也必须映射真实文件系统。
(从 pyfakefs issue 中的答案复制并略微改编)
我正在重构一个库以将 importlib.resources 用于 python 3.7+。我正在使用 importlib_resources 向后移植来实现 python 3.6 兼容性。该代码适用于 pythons 3.6-3.8。但是,使用 pyfakefs 的 pytest 测试在 3.6 中失败。在测试条件下,使用 importlib_resources 的路径 return 被破坏(但在 "real-world" 条件下它们 return 正确)。
一个最小的例子:我有以下库结构:
mypackage
├── mypackage
│ ├── __init__.py
│ ├── bin
│ │ └── __init__.py
│ └── find_bin.py
└── tests
└── test_find_bin.py
在实际的库中,bin 文件夹包含二进制文件(加上一个空 __init__
)。库中其他地方的代码需要一个路径。 find_bin.py
演示了一个将 return 路径的函数:
import sys
if sys.version_info >= (3, 7):
from importlib import resources
else:
import importlib_resources as resources
import mypackage.bin
def find_bin():
init_path_context = resources.path(mypackage.bin, '__init__.py')
with init_path_context as p:
init_path = p
bin_path = init_path.parent
return bin_path
pytest测试test_find_bin.py
:
import pathlib
from mypackage.find_bin import find_bin
def test_findbin(fs):
test_bin = (pathlib.Path(__file__)
.resolve()
.parent.parent
.joinpath('mypackage', 'bin'))
print('test bin is ', test_bin)
expected_bin = find_bin()
print('expected bin is ', expected_bin)
assert not expected_bin.exists()
print('test creating fakefs ', test_bin)
fs.create_dir(test_bin)
assert expected_bin.exists()
Python 3.7+ 在测试中按预期工作。在 python 3.6 中,expected_bin 路径被破坏:
test bin is /Users/geoffreysametz/Documents/mypackage/mypackage/bin # correct
expected bin is /var/folders/bv/m5cg5cp15t38sh8rxx244hp00000gn/T # ?!?!?!
我试图跟踪 find_bin 函数的执行过程,它又长又复杂。但是,我看到 importlib_resources
使用了 python 的 FakeFilesystem class。我的假设是问题是由 importlib_resources
和 pytest 同时使用假文件系统引起的。
我的假设是否正确?是否有解决方法让 pytest 测试使用 importlib_resources 的代码?
pyfakefs 中的假文件系统在测试开始时是空的(除了 tempfile
模块所需的临时文件路径),所以如果你想访问 real 文件系统在你的测试中,你必须 map them into the fake filesystem:
def test_findbin(fs):
test_bin = (pathlib.Path(__file__)
.resolve()
.parent.parent
.joinpath('mypackage', 'bin'))
fs.add_real_directory(test_bin)
...
在你的真实测试中,你事先不知道路径,所以你必须添加一些你知道的父路径来包含你的资源。子目录和文件将在访问时被读取并复制到假文件系统。
关于您在 Python 3.6 中的测试行为:contextlib_package
中的代码首先检查(正确的)路径是否存在,如果不存在(因为它检查假的文件系统,它不会存在),它会创建一个临时文件,它试图在其中复制一些数据 - 因此是输出中的临时路径。
在Python 3.8中,似乎不检查路径是否存在,它只是从正确的路径创建一个Path
对象。当您尝试访问该路径中的某些资源时,这无论如何都会失败,因为它们不存在于假文件系统中,因此在这种情况下您也必须映射真实文件系统。
(从 pyfakefs issue 中的答案复制并略微改编)