前段时间我已开始使用pathlib.Path
,我喜欢使用它。现在我已经习惯了,我已经变得草率而忘记向str
施放论据。
将tox
+ py.test
与基于tmpdir
的临时目录(py._path.local.LocalPath
)一起使用时,通常会发生这种情况:
from pathlib import Path
import pytest
def test_tmpdir(tmpdir):
p = Path(tmpdir) / 'testfile.csv'
我不是每次都插入str()
,而是更普遍地解决这个问题,但却没有。
首先,我尝试创建自己的Path类,该类具有适应的_parse_args
:
import pytest
from py._path.local import LocalPath
from pathlib import Path, PurePath
def Path(Path):
@classmethod
def _parse_args(cls, args):
parts = []
for a in args:
if isinstance(a, PurePath):
parts += a._parts
elif isinstance(a, str):
# Force-cast str subclasses to str (issue #21127)
parts.append(str(a))
elif isinstance(a, LocalPath):
parts.append(str(a))
else:
raise TypeError(
"argument should be a path or str object, not %r"
% type(a))
return cls._flavour.parse_parts(parts)
def test_subclass(tmpdir):
p = Path(tmpdir) / 'testfile.csv'
这会抛出一个TypeError: unsupported operand type(s) for /: 'NoneType' and 'str'
(尝试使用PosixPath
,同样的结果,不希望特定于Linux)。
我试图修补Path
:
import pytest
from pathlib import Path
def add_tmpdir():
from py._path.local import LocalPath
org_attr = '_parse_args'
stow_attr = '_org_parse_args'
def parse_args_localpath(cls, args):
args = list(args)
for idx, a in enumerate(args):
if isinstance(a, LocalPath):
args[idx] = str(a)
return getattr(cls, stow_attr)(args)
if hasattr(Path, stow_attr):
return # already done
setattr(Path, stow_attr, getattr(Path, org_attr))
setattr(Path, org_attr, parse_args_localpath)
add_tmpdir()
def test_monkeypatch_path(tmpdir):
p = Path(tmpdir) / 'testfile.csv'
这会引发AttributeError: type object 'Path' has no attribute '_flavour'
(也就是在修补PurePath的猴子时)。
最后我尝试了Path
:
import pytest
import pathlib
def Path(*args):
from py._path.local import LocalPath
args = list(args)
for idx, a in enumerate(args):
if isinstance(a, LocalPath):
args[idx] = str(a)
return pathlib.Path(*args)
def test_tmpdir_path(tmpdir):
p = Path(tmpdir) / 'testfile.csv'
还提供了AttributeError: type object 'Path' has no attribute '_flavour'
我认为最后一个有效,但我无法重现。 我做错了吗?为什么这么难?
答案 0 :(得分:6)
万一其他人正在研究pytest的tmpdir
路径是否可以与pathlib.Path
完美配合:
使用python 3.6.5
和pytest 3.2.1
,问题中发布的代码可以很好地工作,而无需显式转换为str
:
from pathlib import Path
def test_tmpdir(tmpdir):
p = Path(tmpdir) / 'testfile.csv'
答案 1 :(得分:2)
最后一个(包装)应该有效,我怀疑你实际上在一个py.test
/ tox
运行中测试了所有这些并且那个猴子补丁仍然有效(这可能解释了为什么它有效在某些时候,如果你开始改变全局类的东西,测试文件的顺序等很重要。)
这很难,因为Path
本质上是一个生成器,它会动态决定你是在Windows还是Linux上,并创建一个WindowsPath
resp。 PosixPath
因此。
2015年5月,BDFL Guido van Rossum已经indicated:
听起来像子类化Path应该变得更容易。
但没有发生任何事。在其他标准库中对3.6中的pathlib
的支持已经增加,但是pathlib本身仍然存在相同的问题。
答案 2 :(得分:1)
为方便起见,您可以创建一个夹具来自动进行包装:
@pytest.fixture
def tmppath(tmpdir):
return Path(tmpdir)
然后您可以在测试中使用 tmppath
而不是 tmpdir
。