Skip to content

The class decorated by @from_file loses its original type hint #62

@OpenGHz

Description

@OpenGHz

Here is a possible solution:

`
T = TypeVar("T", bound=BaseModel)

def from_file(
loader: Type[FileBaseSettingsSource],
use_field: Optional[str] = None,
required: bool = True,
):
def decorator(cls: Type[T]) -> Type[T]:
if not issubclass(cls, BaseModel):
raise TypeError("@from_file can only be applied to Pydantic models")
if use_field is not None:
if use_field not in cls.model_fields:
raise ValueError(f"Field {use_field} not found in model {cls.name}")
field_annotation = cls.model_fields[use_field].annotation
if not issubclass(field_annotation, (str, Path)):
raise ValueError(
f"Field {use_field} must be a string or Path to be used as file source"
)

    class DynamicSourceSettings(cls, BaseSettings):  # type: ignore
        __arg_source_field__ = use_field
        __arg_source_required__ = required

        @classmethod
        def settings_customise_sources(
            cls,
            settings_cls: Type[BaseSettings],
            init_settings: PydanticBaseSettingsSource,
            env_settings: PydanticBaseSettingsSource,
            dotenv_settings: PydanticBaseSettingsSource,
            file_secret_settings: PydanticBaseSettingsSource,
        ) -> Tuple[PydanticBaseSettingsSource, ...]:
            source = DynamicFileSource(
                settings_cls,
                loader,
                cast(InitSettingsSource, init_settings).init_kwargs,
                required,
                use_field,
            )
            return (source,)

    # Tell the type checker that we are returning the original class (but we are actually returning the inherited class)
    return cast(Type[T], DynamicSourceSettings)

return decorator

`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions