2016-11-24 12 views
2

Я начал использовать pathlib.Path некоторое время назад, и мне нравится использовать его. Теперь, когда я привык к этому, я стал неаккуратно и забыл привести аргументы в str.pathlib Путь и py.test LocalPath

Это часто происходит при использовании 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

FWIW pytest планирует однажды перейти на путь: https://github.com/pytest-dev/pytest/issues/1260 –

ответ

1

Этот последний (обертывание) должен работать, я подозреваю, что вы действительно протестировали все это в одном прогоне py.test/tox, и этот патч обезьяны все еще действует (это может объяснить, почему это сработало в какой-то момент, порядок тестовые файлы и т. д. имеют значение, если вы начнете менять вещи на глобальных классах).

Это трудно, из-за Path, по существу являющегося генератором, который на лету решает, находитесь ли вы в Windows или Linux и создает WindowsPath соответственно. PosixPath соответственно.

BDFL Гвидо ван Россум уже indicated в мае 2015 года:

Это звучит как подклассы Путь должен быть облегчен.

но ничего не произошло. Поддержка pathlib в 3.6 в других стандартных библиотеках увеличилась, но у самого пути все еще есть те же проблемы.

+0

При тестировании самостоятельно эта упаковка работает! Жаль, что он работает только для первого аргумента, где я надеялся, что изменение _parse_args также может помочь при добавлении сегментов, нет ли шанса на это работать? – Alois

+0

@Alois Это сложнее, чем просто упаковка, но это можно сделать. Вам лучше разместить его как отдельный (отдельный) вопрос.В любом случае вы не хотели бы иметь '/ tmpdir /', поскольку 'tmpdir' является абсолютным путем (' str (tmpdir) 'начинается с'/') – Anthon

 Смежные вопросы

  • Нет связанных вопросов^_^