pydantic / pydantic

Data validation using Python type hints
https://docs.pydantic.dev
MIT License
19.54k stars 1.76k forks source link

PydanticSchemaGenerationError when using os.PathLike[str] #9706

Open unicodestrangely opened 1 week ago

unicodestrangely commented 1 week ago

Initial Checks

Description

Works with plain os.PathLike. Error with os.PathLike[str], os.PathLike[bytes], os.PathLike[Any].

$ python main.py 
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    class Model(pydantic.BaseModel):
  File "pydantic/_internal/_model_construction.py", line 202, in __new__
    complete_model_class(
  File "pydantic/_internal/_model_construction.py", line 539, in complete_model_class
    schema = cls.__get_pydantic_core_schema__(cls, handler)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/main.py", line 626, in __get_pydantic_core_schema__
    return handler(source)
           ^^^^^^^^^^^^^^^
  File "pydantic/_internal/_schema_generation_shared.py", line 82, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 502, in generate_schema
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 753, in _generate_schema_inner
    return self._model_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 580, in _model_schema
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 580, in <dictcomp>
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 916, in _generate_md_field_schema
    common_field = self._common_field_schema(name, field_info, decorators)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 1081, in _common_field_schema
    schema = self._apply_annotations(
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 1825, in _apply_annotations
    schema = get_inner_schema(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_schema_generation_shared.py", line 82, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 1806, in inner_handler
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 758, in _generate_schema_inner
    return self.match_type(obj)
           ^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 840, in match_type
    return self._match_generic_type(obj, origin)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 888, in _match_generic_type
    return self._unknown_type_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pydantic/_internal/_generate_schema.py", line 405, in _unknown_type_schema
    raise PydanticSchemaGenerationError(
pydantic.errors.PydanticSchemaGenerationError: Unable to generate pydantic-core schema for os.PathLike[str]. Set `arbitrary_types_allowed=True` in the model_config to ignore this error or implement `__get_pydantic_core_schema__` on your type to fully support it.

If you got this error by calling handler(<some type>) within `__get_pydantic_core_schema__` then you likely need to call `handler.generate_schema(<some type>)` since we do not call `__get_pydantic_core_schema__` on `<some type>` otherwise to avoid infinite recursion.

For further information visit https://errors.pydantic.dev/2.7/u/schema-for-unknown-type

Example Code

# main.py

import os
import pydantic

class Model(pydantic.BaseModel):
    field: os.PathLike[str]

Python, Pydantic & OS Version

pydantic version: 2.7.3
        pydantic-core version: 2.18.4
          pydantic-core build: profile=release pgo=true
                 install path: pydantic
               python version: 3.11.9 (main, Apr  6 2024, 17:59:24) [GCC 11.4.0]
                     platform: Linux-6.5.0-35-generic-x86_64-with-glibc2.35
             related packages: typing_extensions-4.12.2
                       commit: unknown
sydney-runkle commented 1 week ago

Indeed, looks like a bug! Help welcome here - should be fix in the _std_types_schema.py file.

nix010 commented 1 week ago

@sydney-runkle I can take this one.

nix010 commented 6 days ago

@sydney-runkle so do we expect any certain behaviors that different from os.PathLike for the os.PathLike[str], os.PathLike[bytes] type ? And also what are the limit for xxx in os.PathLike[xxx]? or just bytes and str

sydney-runkle commented 4 days ago

@nix010,

Let's just start with bytes and str for now. I'm not aware of special behaviors that we need to account for at the moment, though we'll probably want to perform validation on the data relevant to the type that PathLike is being parametrized with!

unicodestrangely commented 3 days ago

I think os.PathLike[Any] should be supported as well. Omitting the generic notation equals Any, so os.PathLike is the same as os.PathLike[Any].

nix010 commented 3 days ago

@unicodestrangely I'm a bit hesitate with let's say the case is os.PathLike[Any] and the input is int, should the code raises validation error ?

import os
from typing import Any

from pydantic import BaseModel

class Foo(BaseModel):
    field: os.PathLike[Any]

Foo(field=12345)   #<-- Should this raised validation error ?
nix010 commented 3 days ago

@sydney-runkle I'm not sure if the change is align wiht what is expected but made #9764 anyway to see if it on the right direction!

unicodestrangely commented 3 days ago

@nix010 Yes, it should raise an error. os.PathLike (even [Any]) must have an __fspath__ method (docs).