Проблема с подсказками типов 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)
Я думаю, что понимаю непосредственную причину проблемы, но утверждаю, что этого не должно происходить. Учитывая это, у меня есть несколько вопросов:
- Это идиоматический способ написать этот код?
- Проблема в tempfile, os, pyright или во мне?
- Если я не могу обновить Python, каков наилучший (т.е. наименее неуклюжий) способ подавить ошибку?
1 ответ
Это похоже на ограничение пирита.
Короче говоря, tempfile.TemporaryDirectory
класс типизирован как общий по отношению к AnyStr. Однако в вашем примере кода не указывается общий тип, оставляя его на усмотрение средства проверки типов, чтобы вывести что-то подходящее.
В этом случае, я думаю, у проверщика типов есть несколько разумных вещей:
- Выберите общий тип по умолчанию на основе переменной типа, например 'str' или 'Union[str, bytes]'. Например, mypy по умолчанию выбирает 'str', давая 'tmpfolder' тип 'str'.
- Выберите тип заполнителя, например "Любой", динамический тип или "Без возврата" (он же "низ" или "ничего"). Оба типа являются допустимым подтипом каждого типа, поэтому гарантированно являются действительными заполнителями и не вызывают ошибок в нисходящем направлении. Это то, что делают pyre и pytype - они выводят, что tmpfolder имеет тип Any и ничего соответственно.
- Попытайтесь вывести правильный тип на основе контекста. Некоторые средства проверки типов могут попытаться сделать это, но я не знаю ни одной, которая идеально справилась бы с этим конкретным случаем.
- Сообщите об ошибке и попросите пользователя указать желаемый универсальный тип.
Похоже, что вместо этого pyright просто "просочился" из общей переменной. Возможно, есть принципиальная причина, по которой Pyright решает сделать это, но я не замечаю, но ИМО это похоже на ошибку.
Чтобы ответить на ваши другие вопросы, ваш пример программы является идиоматическим Python, и средства проверки типов в идеале должны поддерживать его без изменений.
Добавление # type: ignore
комментарий к строке с ошибкой - это санкционированный PEP 484 способ подавления сообщений об ошибках. Я недостаточно знаком с pyright, чтобы знать, есть ли у него другой предпочтительный способ подавления ошибок.