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

Adding field-show-examples to show the examples for a field #295

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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: 11 additions & 0 deletions docs/source/users/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,17 @@ Fields
Displays all constraints that are associated with the given pydantic field.


.. config_description:: autopydantic_model
:title: Show Examples
:path: target.configuration.FieldShowExamples
:confpy: autodoc_pydantic_field_show_examples
:directive_option: field-show-examples
:enable: members, field-doc-policy=docstring
:values: True, False

Displays all examples that are associated with the given pydantic field.


.. config_description:: autopydantic_model
:title: Show Alias
:path: target.configuration.FieldShowAlias
Expand Down
5 changes: 5 additions & 0 deletions sphinxcontrib/autodoc_pydantic/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ def full_name(self) -> str:
default='field',
types=str,
),
Config(
name='field_show_examples',
default=True,
types=bool,
),

# general
Config(
Expand Down
18 changes: 18 additions & 0 deletions sphinxcontrib/autodoc_pydantic/directives/autodocumenters.py
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,24 @@ def add_content(
if self.pydantic.options.is_true('field-list-validators'):
self.add_validators()

if self.pydantic.options.is_true('field-show-examples'):
self.add_examples()

def add_examples(self) -> None:
"""Add section showing all defined examples for field."""

field_name = self.pydantic_field_name
examples = self.pydantic.inspect.fields.get_examples(field_name)

if examples:
source_name = self.get_sourcename()
self.add_line(':Examples:', source_name)
for value in examples:
line = f' - {value}'
self.add_line(line, source_name)

self.add_line('', source_name)

def add_constraints(self) -> None:
"""Adds section showing all defined constraints."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
'field-list-validators': option_default_true,
'field-swap-name-and-alias': option_default_true,
'field-doc-policy': option_one_of_factory(OptionsFieldDocPolicy.values()),
'field-show-examples': option_default_true,
'__doc_disable_except__': option_list_like,
}
"""Represents added directive options for :class:`PydanticFieldDocumenter`."""
Expand Down
11 changes: 11 additions & 0 deletions sphinxcontrib/autodoc_pydantic/inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ def get_constraints(self, field_name: str) -> dict[str, Any]:
if getattr(meta, key) is not None
}

def has_examples(self, field_name:str) -> bool:
"""Check if examples are provided in field info."""

return self.get_property_from_field_info(field_name, "examples") is not None

def get_examples(self, field_name: str) -> list[Any]:
"""Get examples for given `field_name`."""

if self.has_examples(field_name):
return self.get_property_from_field_info(field_name, 'examples')

def is_required(self, field_name: str) -> bool:
"""Check if a given pydantic field is required/mandatory. Returns True,
if a value for this field needs to provided upon model creation.
Expand Down
1 change: 1 addition & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
'autodoc_pydantic_validator_list_fields': False,
'autodoc_pydantic_field_list_validators': False,
'autodoc_pydantic_field_show_constraints': False,
'autodoc_pydantic_field_show_examples': False,
'autodoc_pydantic_field_show_alias': False,
'autodoc_pydantic_field_show_required': False,
'autodoc_pydantic_field_show_optional': False,
Expand Down
14 changes: 14 additions & 0 deletions tests/roots/test-base/target/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,20 @@ class FieldSwapNameAndAlias(BaseModel):
"""Field1"""


class FieldShowExamples(BaseModel):
"""FieldShowExamples."""

field: int = Field(1, examples=[2, 3])
"""Field."""


class FieldShowExamplesExtra(BaseModel):
"""FieldShowExamplesExtra."""

field: int = Field(1, examples=[2, 3], json_schema_extra=dict(examples=[4, 5]))
"""Field."""


class ModelErdanticFigureRelated(ModelShowFieldSummary):
"""ModelErdanticFigureRelated."""

Expand Down
4 changes: 4 additions & 0 deletions tests/roots/test-base/target/usage_automodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class AutoModuleSettings(BaseSettings):
default=5, ge=0, le=100, description='Shows constraints within doc string.'
)

field_with_examples: int = Field(0, examples=[123, 546, 789])
"""Shows examples within doc string."""


@field_validator('field_with_validator_and_alias', 'field_plain_with_validator')
def check_max_length_ten(cls, v):
"""Show corresponding field with link/anchor."""
Expand Down
92 changes: 92 additions & 0 deletions tests/test_configuration_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -1632,3 +1632,95 @@ def test_autodoc_pydantic_field_swap_name_and_alias_true_directive_global(parse_
},
)
assert_node(doctree, output_nodes)


def test_autodoc_pydantic_field_show_examples_true(autodocument):
kwargs = dict(
object_path='target.configuration.FieldShowExamples.field', **KWARGS
)

result = [
'',
'.. py:pydantic_field:: FieldShowExamples.field',
' :module: target.configuration',
' :type: int',
'',
' Field.',
'',
' :Examples:',
' - 2',
' - 3',
'',
]

# explicit local
actual = autodocument(options_doc={'field-show-examples': True}, **kwargs)
assert result == actual

# explicit local overwrite global
actual = autodocument(
options_app={'autodoc_pydantic_field_show_examples': False},
options_doc={'field-show-examples': True},
**kwargs,
)
assert result == actual


def test_autodoc_pydantic_field_show_examples_false(autodocument):
kwargs = dict(
object_path='target.configuration.FieldShowExamples.field', **KWARGS
)

result = [
'',
'.. py:pydantic_field:: FieldShowExamples.field',
' :module: target.configuration',
' :type: int',
'',
' Field.',
'',
]

# explicit local
actual = autodocument(options_doc={'field-show-examples': False}, **kwargs)
assert result == actual

# explicit local overwrite global
actual = autodocument(
options_app={'autodoc_pydantic_field_show_examples': True},
options_doc={'field-show-examples': False},
**kwargs,
)
assert result == actual


def test_autodoc_pydantic_field_show_examples_ignore_extra(autodocument):
kwargs = dict(
object_path='target.configuration.FieldShowExamplesExtra.field', **KWARGS
)

result = [
'',
'.. py:pydantic_field:: FieldShowExamplesExtra.field',
' :module: target.configuration',
' :type: int',
'',
' Field.',
'',
' :Examples:',
' - 2',
' - 3',
'',
]

# explicit local
actual = autodocument(options_doc={'field-show-examples': True}, **kwargs)
assert result == actual

# explicit local overwrite global
actual = autodocument(
options_app={'autodoc_pydantic_field_show_examples': False},
options_doc={'field-show-examples': True},
**kwargs,
)
assert result == actual