From 6f7babf611c1f8e54c3917daab32841b256268e9 Mon Sep 17 00:00:00 2001 From: cristianchiriac <80774326+cristianchiriac@users.noreply.github.com> Date: Mon, 28 Sep 2026 22:34:00 +0300 Subject: [PATCH 1/4] Support Pydantic v1 field metadata --- pdoc/_pydantic.py | 11 +++++++++-- test/test__pydantic.py | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/pdoc/_pydantic.py b/pdoc/_pydantic.py index 945537a5..402cb88f 100644 --- a/pdoc/_pydantic.py +++ b/pdoc/_pydantic.py @@ -41,7 +41,9 @@ 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 @@ -49,7 +51,12 @@ def default_value(parent: ClassOrModule, name: str, obj: Any) -> Any: 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 diff --git a/test/test__pydantic.py b/test/test__pydantic.py index 34aa0e74..9b064f5c 100644 --- a/test/test__pydantic.py +++ b/test/test__pydantic.py @@ -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 @@ -39,3 +41,26 @@ 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)) From 3e1256b65456d7a1d1ecd12cb566c455de0f7883 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 28 Sep 2026 19:35:24 +0000 Subject: [PATCH 2/4] [autofix.ci] apply automated fixes --- test/test__pydantic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test__pydantic.py b/test/test__pydantic.py index 9b064f5c..d5a1a5ea 100644 --- a/test/test__pydantic.py +++ b/test/test__pydantic.py @@ -47,7 +47,9 @@ 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") + 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" From fc23be090123489ed7a8acbac8b43f2f6e3120e5 Mon Sep 17 00:00:00 2001 From: cristianchiriac <80774326+cristianchiriac@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:15:25 +0000 Subject: [PATCH 3/4] Add changelog entry for Pydantic v1 support Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Ce8Hr56xHurqiV5wEkVmxj --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d64bb2a6..e0f15295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## Unreleased: pdoc next +- Fix a crash when documenting Pydantic v1 models, and show their field descriptions and defaults. - Fix incorrect ordering of `start-after`/`end-before` in RST include directives. ([#876](https://github.com/mitmproxy/pdoc/pull/876), @JohanKarlbergg) - Support Pydantic [`computed_field`](https://docs.pydantic.dev/2.0/usage/computed_fields/) descriptions ([#855](https://github.com/mitmproxy/pdoc/pull/855), @avhz) From cb2f97acfbfab388a3db043501bbb04b9417ac6c Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 20 Oct 2026 17:17:37 +0000 Subject: [PATCH 4/4] [autofix.ci] apply automated fixes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f15295..977444c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## Unreleased: pdoc next - Fix a crash when documenting Pydantic v1 models, and show their field descriptions and defaults. + ([#901](https://github.com/mitmproxy/pdoc/pull/901), @cristianchiriac) - Fix incorrect ordering of `start-after`/`end-before` in RST include directives. ([#876](https://github.com/mitmproxy/pdoc/pull/876), @JohanKarlbergg) - Support Pydantic [`computed_field`](https://docs.pydantic.dev/2.0/usage/computed_fields/) descriptions ([#855](https://github.com/mitmproxy/pdoc/pull/855), @avhz)