prefer-typed-settings-field
Declare numeric model domains and use typed choices for token-valued defaults.
Why
Bare model numbers omit their valid domain; raw token defaults hide a choice or identifier domain. A primitive annotation can also erase an enum, nominal identifier or URL contract demonstrated by its default.
Fix
Reuse the default's enum or NewType, use a Pydantic URL type with the accepted schemes, and prefer PositiveInt/NonNegativeInt or PositiveFloat/NonNegativeFloat for exact zero bounds. Keep units, aliases and source precedence explicit. Use SecretStr for secrets, existing domain identifiers, nested settings with default_factory, declarative bounds and pure computed properties where their contracts justify them. Validate textual environment values; do not enable blanket strict mode or change coercion, optionality or startup behavior without checking real environment inputs.
Examples
from enum import StrEnumfrom pydantic import Fieldfrom pydantic_settings import BaseSettings
class Mode(StrEnum): CLOUD = "cloud"
class Settings(BaseSettings): mode: str = Field(default=Mode.CLOUD, alias="MODE")from enum import StrEnumfrom pydantic import Fieldfrom pydantic_settings import BaseSettings
class Mode(StrEnum): CLOUD = "cloud"
class Settings(BaseSettings): mode: Mode = Field(default=Mode.CLOUD, alias="MODE")from pydantic import BaseModel
class Audio(BaseModel): duration_seconds: floatfrom pydantic import BaseModel, PositiveFloat
class Audio(BaseModel): duration_seconds: PositiveFloatfrom pydantic_settings import BaseSettings
class Settings(BaseSettings): voice: str = "voice_a"from enum import StrEnumfrom pydantic_settings import BaseSettings
class Voice(StrEnum): MAIN = "voice_a"
class Settings(BaseSettings): voice: Voice = Voice.MAIN