Проблема с подсказками типов Python и стандартными библиотеками

Следующий код работает, как ожидалось, но os.path.join выдает ошибку типа с использованием pyright в VSCode, где показано.

# python 3.6.9
# pyright 1.1.25
# windows 10
# vscode 1.42.1
import os
import tempfile

with tempfile.TemporaryDirectory() as tmpfolder:
    name = "hello.txt"
    path = os.path.join(tmpfolder, name)
    # No overloads for 'os.path.join(tmpfolder, name)' match parameters
    #   Argument types: (TypeVar['AnyStr', str, bytes], Literal['hello.txt'])

print(path)

Я думаю, что понимаю непосредственную причину проблемы, но утверждаю, что этого не должно происходить. Учитывая это, у меня есть несколько вопросов:

  1. Это идиоматический способ написать этот код?
  2. Проблема в tempfile, os, pyright или во мне?
  3. Если я не могу обновить Python, каков наилучший (т.е. наименее неуклюжий) способ подавить ошибку?

1 ответ

Это похоже на ограничение пирита.

Короче говоря, tempfile.TemporaryDirectoryкласс типизирован как общий по отношению к AnyStr. Однако в вашем примере кода не указывается общий тип, оставляя его на усмотрение средства проверки типов, чтобы вывести что-то подходящее.

В этом случае, я думаю, у проверщика типов есть несколько разумных вещей:

  1. Выберите общий тип по умолчанию на основе переменной типа, например 'str' или 'Union[str, bytes]'. Например, mypy по умолчанию выбирает 'str', давая 'tmpfolder' тип 'str'.
  2. Выберите тип заполнителя, например "Любой", динамический тип или "Без возврата" (он же "низ" или "ничего"). Оба типа являются допустимым подтипом каждого типа, поэтому гарантированно являются действительными заполнителями и не вызывают ошибок в нисходящем направлении. Это то, что делают pyre и pytype - они выводят, что tmpfolder имеет тип Any и ничего соответственно.
  3. Попытайтесь вывести правильный тип на основе контекста. Некоторые средства проверки типов могут попытаться сделать это, но я не знаю ни одной, которая идеально справилась бы с этим конкретным случаем.
  4. Сообщите об ошибке и попросите пользователя указать желаемый универсальный тип.

Похоже, что вместо этого pyright просто "просочился" из общей переменной. Возможно, есть принципиальная причина, по которой Pyright решает сделать это, но я не замечаю, но ИМО это похоже на ошибку.


Чтобы ответить на ваши другие вопросы, ваш пример программы является идиоматическим Python, и средства проверки типов в идеале должны поддерживать его без изменений.

Добавление # type: ignoreкомментарий к строке с ошибкой - это санкционированный PEP 484 способ подавления сообщений об ошибках. Я недостаточно знаком с pyright, чтобы знать, есть ли у него другой предпочтительный способ подавления ошибок.

Другие вопросы по тегам