Mypy не обнаруживает защиту типа, почему?Python

Программы на Python
Ответить
Anonymous
 Mypy не обнаруживает защиту типа, почему?

Сообщение Anonymous »

Я пытаюсь научиться использовать защиту типов в моем новом проекте Python в сочетании с настройками pydantic, но mypy, похоже, не улавливает их. Что я здесь делаю не так?
Код:

Код: Выделить всё

import logging
from logging.handlers import SMTPHandler
from functools import lru_cache
from typing import Final, Literal, TypeGuard

from pydantic import EmailStr, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict

SMTP_PORT: Final = 587

class Settings(BaseSettings):
"""
Please make sure your .env contains the following variables:
- BOT_TOKEN - an API token for your bot.
- TOPIC_ID - an ID for your group chat topic.
- GROUP_CHAT_ID - an ID for your group chat.
- ENVIRONMENT - if you intend on running this script on a VPS, this improves logging
information in your production system.

Required only in production:

- SMTP_HOST - SMTP server address (e.g., smtp.gmail.com)
- SMTP_USER - Email username/address for SMTP authentication
- SMTP_PASSWORD - Email password or app-specific password
"""

ENVIRONMENT: Literal["production", "development"]

# Telegram bot configuration
BOT_TOKEN: SecretStr
TOPIC_ID: int
GROUP_CHAT_ID: int

# Email configuration
SMTP_HOST: str | None = None
SMTP_USER: EmailStr | None = None
# If you're using Gmail, this needs to be an app password
SMTP_PASSWORD: SecretStr | None = None

model_config = SettingsConfigDict(env_file="../.env", env_file_encoding="utf-8")

@lru_cache(maxsize=1)
def get_settings() -> Settings:
"""This needs to be lazily evaluated, otherwise pytest gets a circular import."""
return Settings()

type DotEnvStrings = str | SecretStr | EmailStr

def is_all_email_settings_provided(
host: DotEnvStrings | None,
user: DotEnvStrings | None,
password: DotEnvStrings | None,
) -> TypeGuard[DotEnvStrings]:
"""
Type guard that checks if all email settings are provided.

Returns:
True if all email settings are provided as strings, False otherwise.
"""
return all(isinstance(x, (str, SecretStr, EmailStr)) for x in (host, user, password))

def get_logger():
...
settings = get_settings()
if settings.ENVIRONMENT == "development":
level = logging.INFO
else:
# # We only email logging information on failure in production.
if not is_all_email_settings_provided(
settings.SMTP_HOST, settings.SMTP_USER, settings.SMTP_PASSWORD
):
raise ValueError("All email environment variables are required in production.")
level = logging.ERROR
email_handler = SMTPHandler(
mailhost=(settings.SMTP_HOST, SMTP_PORT),
fromaddr=settings.SMTP_USER,
toaddrs=settings.SMTP_USER,
subject="Application Error",
credentials=(settings.SMTP_USER, settings.SMTP_PASSWORD.get_secret_value()),
# This enables TLS - https://docs.python.org/3/library/logging.handlers.html#smtphandler
secure=(),
)
И вот что говорит mypy:

Код: Выделить всё

media_only_topic\media_only_topic.py:122: error: Argument "mailhost" to "SMTPHandler" has incompatible type "tuple[str | SecretStr, int]"; expected "str | tuple[str, int]"  [arg-type]
media_only_topic\media_only_topic.py:123: error: Argument "fromaddr" to "SMTPHandler" has incompatible type "str | None"; expected "str"  [arg-type]
media_only_topic\media_only_topic.py:124: error: Argument "toaddrs" to "SMTPHandler" has incompatible type "str | None"; expected "str | list[str]"  [arg-type]
media_only_topic\media_only_topic.py:126: error: Argument "credentials" to "SMTPHandler" has incompatible type "tuple[str | None, str | Any]"; expected "tuple[str, str] | None"  [arg-type]
media_only_topic\media_only_topic.py:126: error: Item "None" of "SecretStr | None" has no attribute "get_secret_value"  [union-attr]
Found 5 errors in 1 file (checked 1 source file)
Я ожидаю, что mypy здесь правильно прочитает, что мои переменные даже теоретически не могут иметь значение None, но защита типов, похоже, здесь ничего не меняет, независимо от того, сколько раз Я меняю код здесь. Переход на Pyright не имеет никакого значения. Какой подход здесь будет правильным?

Подробнее здесь: https://stackoverflow.com/questions/791 ... -guard-why
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»