Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autodoc_pydantic 2.x doesn't handle autodoc_type_aliases in conf.py correctly #304

Closed
caseyzak24 opened this issue Sep 20, 2024 · 1 comment

Comments

@caseyzak24
Copy link
Contributor

Build Versions

sphinx 7.4.7
pydantic 2.9.2
autodoc-pydantic 2.2.0

Problem

We recently migrated to v2 for pydantic/autodoc_pydantic and the html build now fails with

File "/Users/caseyzak/repos/generation/.venv/lib/python3.10/site-packages/sphinxcontrib/autodoc_pydantic/inspection.py", line 152, in _get_meta_items
    return meta_class.__dict__
AttributeError: 'str' object has no attribute '__dict__'

The full traceback wasn't much more help, so I modified the _get_meta_items method in inspection.py as follows:

    def _get_meta_items(meta_class: Any) -> dict[str, str]:  # noqa: ANN401
        """Helper method to extract constraint names and values from different
        pydantic Metadata objects such as `pydantic.types.Strict`.

        """
        print(meta_class)
        try:
            return meta_class.__dataclass_fields__
        except AttributeError:
            try:
                return meta_class.__dict__
            except AttributeError:
                raise AttributeError(f"{meta_class} is type {type(meta_class).__name__}")

which revealed that the failure occurs on the field type constraint, which is coming up as string instead of a metaclass instance. This seems to be because we use Annotated types for fields as clean way to document field units in our code and docs. To demonstrate:

unit_types.py

from __future__ import annotations
from typing_extensions import Annotated

# note the pattern here, we define a type to be used in the code (for devs benefit). The 2 strings are always
#  1) the type variable name and 2) the path to the variable
unit_types = [
    kW := Annotated[float, "kW", "unit_types.kW"],
    kWh := Annotated[float, "kWh", "unit_types.kWh"],
    V := Annotated[float, "V", "unit_types.V"],
    Wm2 := Annotated[float, "Wm2", "unit_types.Wm2"],
    Whm2 := Annotated[float, "Whm2", "unit_types.Whm2"],
    m2 := Annotated[float, "m2", "unit_types.m2"],
    deg := Annotated[float, "deg", "unit_types.deg"],
    degC := Annotated[float, "degC", "unit_types.degC"],
    dec := Annotated[float, "dec", "unit_types.dec"],
]

conf.py

from generation_models.generation_models.unit_types import unit_types  # noqa: E402
from typing import get_args  # noqa: E402

autodoc_member_order = "bysource"
add_module_names = False
autodoc_type_aliases = {get_args(k)[1]: get_args(k)[2] for k in unit_types}

models.py

from __future__ import annotations
import typing as t
from pydantic import BaseModel
from .unit_types import kW, V, dec, Wm2, deg, degC, kWh, Whm2, m2


class PVTimeSeries(BaseModel):
    r"""-"""

    ghi: t.List[Wm2]

    tracker_rotation_angle: t.Optional[t.List[deg]] = None

    front_poa_nominal: t.Optional[t.List[Wm2]] = None

    front_poa_shaded: t.Optional[t.List[Wm2]] = None

Using pydantic/autodoc-pydantic v1, this would generate docs like this:
image

Given that autodoc_type_aliases is a sphinx autodoc feature and this worked for v1, I assume previously autodoc-pydantic either handed this to sphinx to resolve or just ignored it and let autodoc handle it after (I'm a little unclear on the handling order).

Happy to work on fixing this if I'm pointed in the right direction, or perhaps our approach is just hacky and there is a more canonical way to achieve the same result in v2.

@caseyzak24
Copy link
Contributor Author

This seems to have been solved with the following package upgrades/versions:

sphinx 8.1.3
pydantic 2.9.2
autodoc-pydantic 2.2.0
sphinx-rtd-theme 3.0.1
sphinx-autodoc-typehints 2.5.0

Unfortunately I'm not exactly sure which of these upgrades or additional package installs resolved the issue. I performed them trying to solve a different problem and after doing so checked to see if they resolved this problem and they did. Hopefully this will help others facing a similar issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant