diff --git a/docs/ext/pydantic_autosummary/generate.py b/docs/ext/pydantic_autosummary/generate.py index d2669a10b..4f6b969ce 100644 --- a/docs/ext/pydantic_autosummary/generate.py +++ b/docs/ext/pydantic_autosummary/generate.py @@ -24,6 +24,7 @@ import re import sys from os import path +from pathlib import Path from typing import TYPE_CHECKING, Any, NamedTuple import sphinx.locale @@ -151,7 +152,7 @@ def __init__(self, app: Sphinx) -> None: # ``jinja2.ext.i18n`` extension self.env.install_gettext_translations(app.translator) # type: ignore[attr-defined] - def render(self, template_name: str, context: dict) -> str: + def render(self, template_name: str, context: dict[str, Any]) -> str: """Render a template file.""" try: template = self.env.get_template(template_name) @@ -286,7 +287,7 @@ def generate_autosummary_content( imported_members: bool, app: Any, recursive: bool, - context: dict, + context: dict[str, Any], modname: str | None = None, qualname: str | None = None, ) -> str: @@ -505,10 +506,11 @@ def _get_modules( fullname = name + "." + modname try: module = import_module(fullname) - if module and hasattr(module, "__sphinx_mock__"): - continue except ImportError: pass + else: + if module and hasattr(module, "__sphinx_mock__"): + continue items.append(fullname) if public_members is not None: @@ -529,16 +531,22 @@ def generate_autosummary_docs( app: Any = None, overwrite: bool = True, encoding: str = "utf-8", -) -> None: +) -> list[Path]: + """Generate autosummary documentation for the given sources. + + :returns: list of generated files (both new and existing ones) + """ + assert app is not None, "app is required" + showed_sources = sorted(sources) if len(showed_sources) > 20: showed_sources = showed_sources[:10] + ["..."] + showed_sources[-10:] # ----------- pydantic_autosummary change - logger.info( - __("[pydantic_autosummary] generating autosummary for: %s") - % ", ".join(showed_sources) - ) + # 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 @@ -552,7 +560,8 @@ def generate_autosummary_docs( items = find_autosummary_in_files(sources) # keep track of new files - new_files = [] + new_files: list[Path] = [] + all_files: list[Path] = [] filename_map = app.config.autosummary_filename_map if app else {} @@ -593,9 +602,7 @@ def generate_autosummary_docs( # ----------/ pydantic_autosummary change continue - context: dict[str, Any] = {} - if app: - context.update(app.config.autosummary_context) + context: dict[str, Any] = {**app.config.autosummary_context} content = generate_autosummary_content( name, @@ -611,34 +618,39 @@ def generate_autosummary_docs( qualname, ) - filename = os.path.join(path, filename_map.get(name, name) + suffix) - if os.path.isfile(filename): - with open(filename, encoding=encoding) as f: + file_path = Path(path, filename_map.get(name, name) + suffix) + all_files.append(file_path) + if file_path.is_file(): + with file_path.open(encoding=encoding) as f: old_content = f.read() if content == old_content: continue if overwrite: # content has changed - with open(filename, "w", encoding=encoding) as f: + with file_path.open("w", encoding=encoding) as f: f.write(content) - new_files.append(filename) + new_files.append(file_path) else: - with open(filename, "w", encoding=encoding) as f: + with open(file_path, "w", encoding=encoding) as f: f.write(content) - new_files.append(filename) + new_files.append(file_path) # descend recursively to new files if new_files: - generate_autosummary_docs( - new_files, - output_dir=output_dir, - suffix=suffix, - base_path=base_path, - imported_members=imported_members, - app=app, - overwrite=overwrite, + all_files.extend( + generate_autosummary_docs( + [str(f) for f in new_files], + output_dir=output_dir, + suffix=suffix, + base_path=base_path, + imported_members=imported_members, + app=app, + overwrite=overwrite, + ) ) + return all_files + # -- Finding documented entries in files --------------------------------------- @@ -848,6 +860,15 @@ def get_parser() -> argparse.ArgumentParser: "(default: %(default)s)" ), ) + parser.add_argument( + "--remove-old", + action="store_true", + dest="remove_old", + default=False, + help=__( + "Remove existing files in the output directory that were not generated" + ), + ) return parser @@ -863,11 +884,9 @@ def main(argv: Sequence[str] = (), /) -> None: if args.templates: app.config.templates_path.append(path.abspath(args.templates)) - app.config.autosummary_ignore_module_all = ( # type: ignore[attr-defined] - not args.respect_module_all - ) + app.config.autosummary_ignore_module_all = not args.respect_module_all - generate_autosummary_docs( + written_files = generate_autosummary_docs( args.source_file, args.output_dir, "." + args.suffix, @@ -875,6 +894,19 @@ def main(argv: Sequence[str] = (), /) -> None: app=app, ) + if args.remove_old: + for existing in Path(args.output_dir).glob(f"**/*.{args.suffix}"): + if existing not in written_files: + try: + existing.unlink() + except OSError as exc: + logger.warning( + __("Failed to remove %s: %s"), + existing, + exc.strerror, + type="autosummary", + ) + if __name__ == "__main__": main(sys.argv[1:]) diff --git a/docs/ext/pydantic_autosummary/pydantic.py b/docs/ext/pydantic_autosummary/pydantic.py index 2bdf5132d..4c4a9fc8a 100644 --- a/docs/ext/pydantic_autosummary/pydantic.py +++ b/docs/ext/pydantic_autosummary/pydantic.py @@ -19,7 +19,7 @@ def _is_enum_or_enum_member(annotation: Any) -> bool: def _format_annotation(annotation: Any) -> str: - return f"{annotation.__module__}.{annotation.__qualname__}" + return f"{annotation.__qualname__}" def _resolve_pydantic_field_annotations(annotation: Any) -> list[str]: