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

DOC: Auto-generate Pydantic model documentation #705

Merged
merged 1 commit into from
Jun 27, 2024

Conversation

mferrera
Copy link
Collaborator

@mferrera mferrera commented Jun 20, 2024

Resolves #618
Resolves #591
Resolves #695

This PR adds auto-generated documentation for the Pydantic model, representing it as a nested hierarchy in the same way the Pydantic model describes it.

It does this by copying and modifying the Sphinx autosummary extension to handle Pydantic specific things.

  • Risk: this is a possible maintenance burden when Sphinx updates
  • But: it should be lighter than other methods of documenting the model
  • Incompatibilities aren't a given with updates and should be easy to adapt if they are

It collects the previous datamodel documentation to the same place, removes a large section describing the model, and makes some small additions to include the links to the new documentation.

Unfortunately when building the docs a large number of warnings occur, and a smaller number of errors. The warnings are not avoidable because, f.eks., we want to generate a User doc wherever a one appears in the model (multiple places), not have a single reference to it in the abstract.

The errors are a result of

autoclass_content = "class"

in conf.py, so that Pydantic models don't display the BaseModel.__init__ docstring from pydantic (see this). I think they are a false positive stemming from BaseModel, but am not certain.

pydantic__doc

@mferrera mferrera self-assigned this Jun 20, 2024
@mferrera mferrera force-pushed the model-docs branch 2 times, most recently from 6a272df to cdbe036 Compare June 25, 2024 12:44
@mferrera mferrera changed the title WIP nested pydantic docs DOC: Auto-generate Pydantic model documentation Jun 25, 2024
@mferrera mferrera marked this pull request as ready for review June 25, 2024 12:49
Comment on lines +872 to +874
# ----------- pydantic_autosummary change
from .generate import generate_autosummary_docs
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is a direct copy of autosummary, and this is the only change in it (it was previously sphinx.autosummary.generate or so), therefore I don't think the rest of this file needs to be reviewed.

There were very minor changes just to adapt to our ruff linting.

Comment on lines +44 to +53
# ----------- pydantic_autosummary change
from . import (
ImportExceptionGroup,
get_documenter,
import_by_name,
import_ivar_by_name,
)
from .pydantic import set_pydantic_model_fields

# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is also a direct copy from autosummary, and all changes I made are marked here.

The first import set just made the path relative over sphinx.autosummary, but importing from .pydantic import set_pydantic_model_fields was my addition.

Comment on lines +136 to +138
# ----------- pydantic_autosummary change
system_templates_path = [os.path.join(os.path.dirname(__file__), "templates")]
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changed the templates path to use the one embedded in the same directory over the one shipped with Sphinx.

Comment on lines +215 to +225
# ----------- pydantic_autosummary change
logger.warning(
__(
"pydantic_autosummary: failed to determine %r to be documented, "
"the following exception was raised:\n%s"
),
name,
exc,
type="autosummary",
)
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just changed the logger to use pydantic_autosummary: instead of autosummary:

Comment on lines +314 to +321
# ----------- pydantic_autosummary change
ns["pydantic_models"], ns["all_pydantic_models"] = _get_members(
doc, app, obj, {"pydantic_model"}, imported=imported_members
)
ns["pydantic_settings"], ns["all_pydantic_settings"] = _get_members(
doc, app, obj, {"pydantic_settings"}, imported=imported_members
)
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added by me

Comment on lines +382 to +385
# ----------- pydantic_autosummary change
if doc.objtype == "pydantic_model":
set_pydantic_model_fields(ns, obj)
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Takes us to where new code was added, pydantic.py

Comment on lines +406 to +416
# ----------- pydantic_autosummary change
logger.warning(
__(
"pydantic_autosummary: failed to determine %r to be documented, "
"the following exception was raised:\n%s"
),
name,
exc,
type="autosummary",
)
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just changed the logger to use pydantic_autosummary: instead of autosummary:

Comment on lines +537 to +544
# ----------- pydantic_autosummary change
logger.info(
__("[pydantic_autosummary] generating autosummary for: %s")
% ", ".join(showed_sources)
)
if output_dir:
logger.info(__("[pydantic_autosummary] writing to %s") % output_dir)
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just changed the logger to use pydantic_autosummary: instead of autosummary:

Comment on lines +584 to +593
# ----------- pydantic_autosummary change
logger.warning(
__(
"[pydantic_autosummary] failed to import %s.\n"
"Possible hints:\n%s"
),
entry.name,
"\n".join(errors),
)
# ----------/ pydantic_autosummary change
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just changed the logger to use pydantic_autosummary: instead of autosummary:

@@ -0,0 +1,64 @@
from __future__ import annotations
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything in this file was added by me, not pre-existing

@@ -0,0 +1,5 @@
{{ fullname | escape | underline}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default autosummary base template, not written by me

@@ -0,0 +1,29 @@
{{ fullname | escape | underline}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, not written by me

@@ -0,0 +1,60 @@
{{ fullname | escape | underline}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And same here.

@@ -0,0 +1,51 @@
{{ name | escape | underline}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New template added by me

Comment on lines +19 to +25
:members:
:inherited-members: BaseModel
:model-show-config-summary: False
:model-show-json: False
:model-show-validator-members: False
:model-show-validator-summary: False
:field-list-validators: False
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These options descriptions are documented here. If we make a parallel model documentation for ourselves, some of these may want to be removed, hence they were not set in conf.py instead.

Comment on lines +85 to +87
"navigation_depth": -1,
"collapse_navigation": False,
"titles_only": True,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These allow the sidebar menu expansion to function as we wanted them to

Comment on lines +11 to +12
The FMU data model is described using a `Pydantic <https://pydantic.dev/>`__ model
which programmatically generates a `JSON Schema <https://json-schema.org/>`__.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This text is mostly a copy of the previous datamodel.rst, with small changes like this

Comment on lines +20 to +36
Data model documentation
========================

There are two closely related data models represented here: metadata generated from
an FMU realization and metadata generated on a case level. The structure and
documentation of these two models can be inspected from here.

.. autosummary::
:toctree: model/
:recursive:


.. toctree::
:maxdepth: -1

fmu.dataio.datastructure.meta.meta.FMUDataClassMeta
fmu.dataio.datastructure.meta.meta.FMUCaseClassMeta
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this

Comment on lines +23 to +25
from fmu.dataio._definitions import SCHEMA, SOURCE, VERSION
from fmu.dataio.datastructure.meta import meta

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just ruff

This implements a fork/copy of autosummary, stored internally, to
generate hierarchically structured documentation for the Pydantic model
that represents the metadata.
Copy link
Collaborator

@jcrivenaes jcrivenaes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice and impressive work. I installed it locally and it is somewhat annoying with all the WARNINGS and ERROR messages like ERROR: Content block expected for the "raw" directive; none found., and I propose to take further actions on solving this soon.

@mferrera
Copy link
Collaborator Author

Thanks, and agreed. I made #711 and will continue digging into it cause I dislike the flood of messages too.

@mferrera mferrera merged commit 63b6b3e into equinor:main Jun 27, 2024
13 checks passed
@mferrera mferrera deleted the model-docs branch June 27, 2024 05:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants