Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions pdoc/_pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,22 @@ def default_value(parent: ClassOrModule, name: str, obj: Any) -> Any:
For all other objects, return `obj` as-is.
"""
if is_pydantic_model(parent):
pydantic_fields = parent.__pydantic_fields__
pydantic_fields = getattr(parent, "__pydantic_fields__", None)
if pydantic_fields is None:
pydantic_fields = parent.__fields__
return pydantic_fields[name].default if name in pydantic_fields else obj

return obj


def get_field_docstring(parent: ClassOrModule, field_name: str) -> str | None:
if is_pydantic_model(parent):
if field := parent.__pydantic_fields__.get(field_name, None):
pydantic_fields = getattr(parent, "__pydantic_fields__", None)
if pydantic_fields is None:
if field := parent.__fields__.get(field_name):
return getattr(field, "field_info", field).description
return None
if field := pydantic_fields.get(field_name):
return field.description
if computed := parent.__pydantic_computed_fields__.get(field_name, None):
return computed.description
Expand Down
27 changes: 27 additions & 0 deletions test/test__pydantic.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from functools import cached_property

import pydantic
import pydantic.v1 as pydantic_v1

from pdoc import _pydantic
from pdoc import extract
import pdoc.doc


Expand Down Expand Up @@ -39,3 +41,28 @@ def test_with_pydantic(monkeypatch):
assert not _pydantic.is_pydantic_model(pdoc.doc.Module)
assert _pydantic.get_field_docstring(pdoc.doc.Module, "kind") is None
assert _pydantic.default_value(pdoc.doc.Module, "kind", "module") == "module"


def test_with_pydantic_v1(monkeypatch, tmp_path):
monkeypatch.setattr(_pydantic, "pydantic", pydantic_v1)

class LegacyModel(pydantic_v1.BaseModel):
name: str = pydantic_v1.Field(
default="Jane Doe", description="legacy description"
)

assert _pydantic.is_pydantic_model(LegacyModel)
assert _pydantic.get_field_docstring(LegacyModel, "name") == "legacy description"
assert _pydantic.get_field_docstring(LegacyModel, "unknown") is None
assert _pydantic.default_value(LegacyModel, "name", None) == "Jane Doe"
assert _pydantic.default_value(LegacyModel, "unknown", "fallback") == "fallback"

module_file = tmp_path / "legacy_model.py"
module_file.write_text(
"from pydantic.v1 import BaseModel, Field\n"
"class LegacyModel(BaseModel):\n"
" name: str = Field(default='Jane Doe', description='legacy description')\n"
)
module = extract.load_module(extract.parse_spec(module_file))
assert "LegacyModel" in pdoc.doc.Module(module).members
assert "legacy description" in pdoc.pdoc(str(module_file))
Loading