From 25321c6e6939f27e9889aa58021b4501102b004b Mon Sep 17 00:00:00 2001 From: moritzmeister Date: Wed, 30 Sep 2020 14:00:11 +0200 Subject: [PATCH 1/3] make autogenerated substition modular --- keras_autodoc/autogen.py | 13 +++++++++---- keras_autodoc/utils.py | 22 ++++++++++++++++------ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/keras_autodoc/autogen.py b/keras_autodoc/autogen.py index bc7c5d9..0ee000b 100644 --- a/keras_autodoc/autogen.py +++ b/keras_autodoc/autogen.py @@ -47,7 +47,7 @@ class DocumentationGenerator: titles_size: `"#"` signs to put before a title in the generated markdown. """ def __init__(self, - pages: Dict[str, list] = {}, + pages: Dict[str, List[str]] = {}, project_url: Union[str, Dict[str, str]] = None, template_dir=None, examples_dir=None, @@ -79,11 +79,16 @@ def generate(self, dest_dir): if self.template_dir: shutil.copytree(self.template_dir, dest_dir) + replace_final_tag = False + for file_path, elements in self.pages.items(): - markdown_text = '' for element in elements: - markdown_text += self._render(element) - utils.insert_in_file(markdown_text, dest_dir / file_path) + replace_final_tag = utils.insert_in_file( + self._render(element), dest_dir / file_path, "{{" + element + "}}") + + # replace final autogenerated tag + if replace_final_tag: + utils.insert_in_file("", dest_dir / file_path, "{{autogenerated}}") if self.examples_dir is not None: copy_examples(self.examples_dir, dest_dir / "examples") diff --git a/keras_autodoc/utils.py b/keras_autodoc/utils.py index 4c1d2ee..094e13f 100644 --- a/keras_autodoc/utils.py +++ b/keras_autodoc/utils.py @@ -12,22 +12,32 @@ def count_leading_spaces(s): return 0 -def insert_in_file(markdown_text, file_path): +def insert_in_file(markdown_text, file_path, tag): """Save module page. Either insert content into existing page, or create page otherwise.""" + replace_final_tag = False if file_path.exists(): template = file_path.read_text(encoding="utf-8") - if "{{autogenerated}}" not in template: - raise RuntimeError(f"Template found for {file_path} but missing " - f"{{autogenerated}} tag.") - markdown_text = template.replace("{{autogenerated}}", markdown_text) - print("...inserting autogenerated content into template:", file_path) + if tag in template: + markdown_text = template.replace(tag, markdown_text) + print(("...inserting autogenerated content " + "for tag {0} into template:").format(tag), file_path) + elif "{{autogenerated}}" in template: + markdown_text = template.replace( + "{{autogenerated}}", markdown_text + "{{autogenerated}}") + print(("...appending autogenerated content " + "for {0} to template:").format(tag), file_path) + replace_final_tag = True + else: + raise RuntimeError(("Template found for {0} but missing " + "{{{{autogenerated}}}} or {1} tag.").format(file_path, tag)) else: print("...creating new page with autogenerated content:", file_path) os.makedirs(file_path.parent, exist_ok=True) file_path.write_text(markdown_text, encoding="utf-8") + return replace_final_tag def code_snippet(snippet): From 3c9c8372b0f0e8bb222936f26b3fd46bdd11eab5 Mon Sep 17 00:00:00 2001 From: moritzmeister Date: Wed, 30 Sep 2020 15:01:50 +0200 Subject: [PATCH 2/3] fix entirely autogenerated files --- keras_autodoc/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/keras_autodoc/utils.py b/keras_autodoc/utils.py index 094e13f..fa3e1ca 100644 --- a/keras_autodoc/utils.py +++ b/keras_autodoc/utils.py @@ -34,6 +34,7 @@ def insert_in_file(markdown_text, file_path, tag): raise RuntimeError(("Template found for {0} but missing " "{{{{autogenerated}}}} or {1} tag.").format(file_path, tag)) else: + markdown_text = markdown_text + "{{autogenerated}}" print("...creating new page with autogenerated content:", file_path) os.makedirs(file_path.parent, exist_ok=True) file_path.write_text(markdown_text, encoding="utf-8") From 576b7d10e8d77754d34939ee0c7664e127478ecb Mon Sep 17 00:00:00 2001 From: moritzmeister Date: Wed, 21 Oct 2020 17:41:57 +0200 Subject: [PATCH 3/3] revert previous implementation and update according to maintainers --- keras_autodoc/autogen.py | 58 +++++++++++++++++++++++++++++----------- keras_autodoc/utils.py | 32 +++++++++++----------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/keras_autodoc/autogen.py b/keras_autodoc/autogen.py index 0ee000b..b021d6b 100644 --- a/keras_autodoc/autogen.py +++ b/keras_autodoc/autogen.py @@ -1,7 +1,7 @@ import shutil import pathlib -from inspect import getdoc, isclass, getfullargspec -from typing import Dict, Union, List +from inspect import getdoc, isclass +from typing import Dict, Union, List, get_type_hints from .docstring import process_docstring from .examples import copy_examples @@ -19,6 +19,8 @@ class DocumentationGenerator: are lists of strings, functions /classes / methods names with dotted access to the object. For example, `pages = {'my_file.md': ['keras.layers.Dense']}` is valid. + Values can also be dictionaries, introducing an extra level to map + custom tags to lists of elements to be documented. project_url: The url pointing to the module directory of your project on GitHub. This will be used to make a `[Sources]` link. template_dir: Where to put the markdown files which will be copied and @@ -47,7 +49,7 @@ class DocumentationGenerator: titles_size: `"#"` signs to put before a title in the generated markdown. """ def __init__(self, - pages: Dict[str, List[str]] = {}, + pages: Dict[str, list] = {}, project_url: Union[str, Dict[str, str]] = None, template_dir=None, examples_dir=None, @@ -69,6 +71,9 @@ def generate(self, dest_dir): # Arguments dest_dir: Where to put the resulting markdown files. + + # Raises + TypeError: if elements are not specified as list or dict of lists. """ dest_dir = pathlib.Path(dest_dir) print("Cleaning up existing sources directory.") @@ -79,16 +84,22 @@ def generate(self, dest_dir): if self.template_dir: shutil.copytree(self.template_dir, dest_dir) - replace_final_tag = False - for file_path, elements in self.pages.items(): - for element in elements: - replace_final_tag = utils.insert_in_file( - self._render(element), dest_dir / file_path, "{{" + element + "}}") - - # replace final autogenerated tag - if replace_final_tag: - utils.insert_in_file("", dest_dir / file_path, "{{autogenerated}}") + if isinstance(elements, list): + self._render_list_and_insert(elements, dest_dir / file_path) + elif isinstance(elements, dict): + for tag, grouped_elements in elements.items(): + if isinstance(grouped_elements, list): + self._render_list_and_insert( + grouped_elements, dest_dir / file_path, tag) + else: + raise TypeError( + "Expected list of elements to be documented, is of type {}: {}" + .format(type(grouped_elements), grouped_elements)) + else: + raise TypeError( + "Expected list of elements to be documented, is of type {}: {}" + .format(type(elements), elements)) if self.examples_dir is not None: copy_examples(self.examples_dir, dest_dir / "examples") @@ -116,6 +127,12 @@ def _render(self, element): return self._render_from_object(object_, signature_override) + def _render_list_and_insert(self, element_list, file_path, tag="autogenerated"): + markdown_text = '' + for element in element_list: + markdown_text += self._render(element) + utils.insert_in_file(markdown_text, file_path, tag) + def _render_from_object(self, object_, signature_override: str): subblocks = [] if self.project_url is not None: @@ -129,14 +146,23 @@ def _render_from_object(self, object_, signature_override: str): docstring = getdoc(object_) if docstring: - docstring = self.process_docstring( - docstring, getfullargspec(object_).annotations - ) + if isclass(object_): + type_hints = get_type_hints(object_.__init__) + else: + type_hints = get_type_hints(object_) + docstring = self.process_docstring(docstring, type_hints) subblocks.append(docstring) return "\n\n".join(subblocks) + '\n\n----\n\n' def _fill_aliases(self, extra_aliases): - for list_elements in self.pages.values(): + for elements in self.pages.values(): + if isinstance(elements, dict): + # collect all lists of elements to be documented + list_elements = [] + for element in elements.values(): + list_elements += element + else: + list_elements = elements for element_as_str in list_elements: element = utils.import_object(element_as_str) if not isclass(element): diff --git a/keras_autodoc/utils.py b/keras_autodoc/utils.py index fa3e1ca..60941c0 100644 --- a/keras_autodoc/utils.py +++ b/keras_autodoc/utils.py @@ -16,29 +16,27 @@ def insert_in_file(markdown_text, file_path, tag): """Save module page. Either insert content into existing page, - or create page otherwise.""" - replace_final_tag = False + or create page otherwise. + + # Arguments + markdown_text: text to be inserted in file. + file_path: path to file to insert text in. + tag: a tag name without parenthesis to replace with content. + """ + tag_par = "{{" + tag + "}}" if file_path.exists(): template = file_path.read_text(encoding="utf-8") - if tag in template: - markdown_text = template.replace(tag, markdown_text) - print(("...inserting autogenerated content " - "for tag {0} into template:").format(tag), file_path) - elif "{{autogenerated}}" in template: - markdown_text = template.replace( - "{{autogenerated}}", markdown_text + "{{autogenerated}}") - print(("...appending autogenerated content " - "for {0} to template:").format(tag), file_path) - replace_final_tag = True - else: - raise RuntimeError(("Template found for {0} but missing " - "{{{{autogenerated}}}} or {1} tag.").format(file_path, tag)) + if tag_par not in template: + raise RuntimeError(f"Template found for {file_path} but missing " + f"{tag_par} tag.") + markdown_text = template.replace(tag_par, markdown_text) + print( + f"...inserting autogenerated content for tag {tag_par} into template:", + file_path) else: - markdown_text = markdown_text + "{{autogenerated}}" print("...creating new page with autogenerated content:", file_path) os.makedirs(file_path.parent, exist_ok=True) file_path.write_text(markdown_text, encoding="utf-8") - return replace_final_tag def code_snippet(snippet):