-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Closed
Labels
Description
Initial Checks
- I have searched GitHub for a duplicate issue and I'm sure this is something new
- I have searched Google & StackOverflow for a solution and couldn't find anything
- I have read and followed the docs and still think this is a bug
- I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)
Description
Subclassing Path
seems to be not possible directly.
However, the documentation states that FilePath
is
like Path, but the path must exist and be a file
That's not correct when it comes to defaults in models. See the example.
The instantiation of FilePath
fails here.
I am not aware of an immediate solution and I think that, at least, the documentation should have a note about that special behaviour.
This is the error:
def test_takes_default():
> assert str(DefaultExists().cert) == exists
test_.py:21:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
pydantic/main.py:340: in pydantic.main.BaseModel.__init__
???
pydantic/main.py:1067: in pydantic.main.validate_model
???
pydantic/fields.py:439: in pydantic.fields.ModelField.get_default
???
test_.py:12: in <lambda>
default_factory=lambda: p.FilePath(exists),
../../../../../.pyenv/versions/3.9.15/lib/python3.9/pathlib.py:1082: in __new__
self = cls._from_parts(args, init=False)
../../../../../.pyenv/versions/3.9.15/lib/python3.9/pathlib.py:707: in _from_parts
drv, root, parts = self._parse_args(args)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls = <class 'pydantic.types.FilePath'>, args = ('/etc/hosts',)
@classmethod
def _parse_args(cls, args):
# This is useful when you don't want to create an instance, just
# canonicalize some constructor arguments.
parts = []
for a in args:
if isinstance(a, PurePath):
parts += a._parts
else:
a = os.fspath(a)
if isinstance(a, str):
# Force-cast str subclasses to str (issue #21127)
parts.append(str(a))
else:
raise TypeError(
"argument should be a str object or an os.PathLike "
"object returning str, not %r"
% type(a))
> return cls._flavour.parse_parts(parts)
E AttributeError: type object 'FilePath' has no attribute '_flavour'
../../../../../.pyenv/versions/3.9.15/lib/python3.9/pathlib.py:700: AttributeError
Example Code
import typing as t
import pydantic as p
import pytest
exists = "/etc/hosts"
exists_not = "/etc/blahosts"
class DefaultExists(p.BaseModel):
cert: t.Optional[p.FilePath] = p.Field(
default_factory=lambda: p.FilePath(exists),
)
def test_can_pass_value():
assert str(DefaultExists(cert=exists).cert) == exists
def test_takes_default():
assert str(DefaultExists().cert) == exists
def test_fails_if_not_exists():
with pytest.raises(ValueError):
DefaultExists(cert=exists_not)
Python, Pydantic & OS Version
pydantic version: 1.10.5
pydantic compiled: True
install path: /Users/cleancoder/Library/Caches/pypoetry/virtualenvs/juice-auth-v2-3il_93qV-py3.9/lib/python3.9/site-packages/pydantic
python version: 3.9.15 (main, Nov 14 2022, 08:33:16) [Clang 14.0.0 (clang-1400.0.29.201)]
platform: macOS-12.6-arm64-arm-64bit
optional deps. installed: ['dotenv', 'email-validator', 'typing-extensions']
Affected Components
- Compatibility between releases
- Data validation/parsing
- Data serialization -
.model_dump()
and.model_dump_json()
- JSON Schema
- Dataclasses
- Model Config
- Field Types - adding or changing a particular data type
- Function validation decorator
- Generic Models
- Other Model behaviour -
model_construct()
, pickling, private attributes, ORM mode - Plugins and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.