/docstring-to-markdown

Export Google DocString to Markdown

Primary LanguagePythonGNU General Public License v3.0GPL-3.0


docstring2md:

Generating documentation from code can be a tedious and time-consuming task. By offering a simple and easy-to-use tool, this package aims to make the process of creating documentation more efficient. It allows users to extract useful information, such as function descriptions and input/output specifications, directly from the source code (DocStrings). This can save a lot of time and effort that would otherwise be spent manually writing documentation. In addition, having documentation automatically generated from code ensures that it stays up-to-date as the codebase changes. Overall, this package provides a convenient solution for generating high-quality documentation for Python projects. All the installation process has been rebuilt with Makefile and pyproject.toml.

Why ?:

We can find a lot of tools to generate docs from code, but we want something quick and easy to set up. This tool can be used on python file or python package.

Semantic analysis and tree traversal are not really my passions ^^, but these types of tools are still very interesting. Some time has passed since the first version. I admit that Python had started to introduce typing, but it was, not yet widespread. There have also been significant changes in the deployment of packages, and since the script setup.py has no reason to exist. I have therefore migrated to the TOML file and adapted the META import libraries. It's true that I might have done this sooner, but I ran out of time and was always using somewhat outdated versions of Python. Changes in the language are constant. This new version is therefore a complete refresh, allowing me to be more in line with what is currently being done in the Python ecosystem.

Use:

Use the script:

Usage: export_docstring2md [-h] [--version] [--debug | --quiet]
                           [--logfile LOGFILE] [--toc] [--private-def]
                           -p PACKAGE [-o OUTPUT_FILE] [-tml TOML_FILE]
                           [-td TODO_FILE] [-mmd MERMAID_FILE]

This script is provided by docstring2md package.
It exports google docstrings from python module to a Markdown file in order
to generate README.

Options:
  -h, --help            show this help message and exit
  --version             show version and exit
  --debug               print debug messages to stderr
  --quiet               print error messages to stderr
  --logfile LOGFILE     /path/to/file.log
  --toc                 Enable the table of contents
  --private-def         Enable the table of contents

Required Arguments:
  -p, --package PACKAGE
                        define the /path/to/the/package or
                        <package_name>

Optional Arguments:
  -o, --output-file OUTPUT_FILE
                        /path/to/output/file (README.md)
  -tml, --toml-file TOML_FILE
                        /path/to/toml/file.toml
  -td, --todo-file TODO_FILE
                        /path/to/todo/file.md
  -mmd, --mermaid-file MERMAID_FILE
                        /path/to/mermaid/file.mmd

COMPATIBILITY:
    Python 3.7+ - https://www.python.org/
EXIT STATUS:
    This script exits 0 on success, and >0 if an error occurs:
    - EX_OK: 0 -> success
    - EX_CONFIG: 78 -> config error
    - EX_OSFILE: 72 -> module not found
    - EX_CANTCREAT: 73 -> can not create the file
    - EX_IOERR: 74 -> write error

Compatibility:

Python 3.7+

Setup:

  • User:

Get the package:

git clone https://github.com/francois-le-ko4la/docstring-to-markdown.git

Change to the folder:

cd docstring-to-markdown

Install with make on Linux/Unix/MacOS or use pip3 otherwise:

make install
  • Dev environment:

Get the package:

git clone https://github.com/francois-le-ko4la/docstring-to-markdown.git

Change to the folder:

cd docstring-to-markdown

Create your environment with all dev prerequisites and install the package:

make venv
source venv/bin/activate
make dev

Test:

This module has been tested and validated on Ubuntu. Test is available if you set up the package with dev environment.

make test

License:

This package is distributed under the GPLv3 license

Todo:

  • Create the project
  • Write code and tests
  • Test installation and requirements (setup.py and/or Makefile)
  • Test code
  • Validate features
  • Add-on : decorator
  • Add-on : class properties
  • Add-on : runtime & requirements
  • Add-on : toc
  • Add-on : remove inspect library and use AST
  • Add-on : improve global performance (x3)
  • Write Doc/stringdoc
  • Run PEP8 validation
  • Clean & last check
  • Release 0.4.1
  • Rebuild the cli argument
  • Rebuild logging management and add more debug
  • Rebuild the package management through pyproject.toml
  • Rebuild the Makefile
  • Add-on : typing analysis
  • Create JSON module example
  • Finish the typing
  • AST optimisation
  • Improve CONST
  • improve doctest look & feel
  • homogeneous doc btw Class and Function
  • Include import in init file
  • Improve the docstring module (MD format is not standard ^^)
  • Move the todo from init to a dedicated file (new option)
  • Use Enum class to define ExitStatus, Const and Tag
  • Fix an issue on Atttributes management
  • Fix decorator argument : add ()
  • Test
  • Release 0.5.0
  • Detect and fix issue on Constant - Improve type detection/extraction
  • Fix pyproject.toml
  • Release 0.5.1

Dev notes

TOML file:

# -*- coding: utf-8 -*-
[project]
name = "docstring2md"
version = "0.5.1"
authors = [
  {name = "ko4la" }
]
description = "Docstring extractor to generate readme."
license = {file = "LICENSE"}
readme = "README.md"
requires-python = ">=3.7"
classifiers = [
    "Development Status :: 5 - Stable",
    "Environment :: Console",
    "Intended Audience :: Developers",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.7",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3 :: Only",
    "OSI Approved :: GNU General Public License v3 (GPLv3)",
]
dependencies = [
    "rich>=12.6.0",
    "rich_argparse>=0.6.0",
    "importlib-metadata ~= 1.0 ; python_version < '3.8'"
    ]

[project.optional-dependencies]
dev = [
    "pycodestyle>=2.3.1",
    "pytest>=7.2.0",
    "pylint",
    "mypy",
    "pydocstyle",
    "pytest-pylint",
    "pytest-pycodestyle",
    "pytest-mypy",
    "pytest-pydocstyle",
    "pytest-isort"]

[project.urls]
"Homepage" = "https://github.com/francois-le-ko4la/docstring-to-markdown"

[project.scripts]
export_docstring2md = "docstring2md.cli:run"

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[tool.pytest.ini_options]
minversion = "7.2"
addopts = [
    "-v",
    "--pycodestyle",
    "--doctest-modules",
    "--mypy",
    "--pydocstyle",
    "--pylint",
    "--isort",
    "--strict-markers"
]
xfail_strict = true
filterwarnings = [
    "ignore:.*U.*mode is deprecated:DeprecationWarning",
    "ignore::DeprecationWarning"]
[tool.mypy]
disallow_any_generics = true
disallow_untyped_defs = true
warn_redundant_casts = true
strict_equality = true


UML Diagram:

classDiagram
  class DocString2MDOptions {
    output
    private_def
    toc
    todo
    toml
    uml
  }
  class EventMSG {
    debug
    error
    info
    warning
  }
  class MyFile {
    exists
    path
    status
    absolute() str
    read() str
    resolve() str
    set_path(path: Optional[str]) MyFile
    write(data: str) ExitStatus
  }
  class NodeVisitor {
    generic_visit(node)
    visit(node)
    visit_Constant(node)
  }
  class ExitStatus {
    name
  }
  class PytMod {
    module
    node_lst
    pkg_main_docstring
    ismodule() bool
    read() None
  }
  class Enum {
    name()
    value()
  }
  class IntEnum {
  }
  class ReprEnum {
  }
  class Const {
    name
  }
  class EventMSG {
    debug : str
    error : str
    info : str
    warning : str
  }
  class ExitStatus {
    name
  }
  class LogMessages {
    args
    dump
    elapse_time
    file_not_found
    io_err
    logfile
    new_class
    new_func
    new_module
    node_link_analysis_beg
    node_link_analysis_end
    python
    pytmod
    pytmod_extract
    pytmod_mod
    pytmod_script
    result
    unknown_type_of_node
    write_doc
  }
  class LoggingSetup {
    default_format : str
    default_level : str
    encoding : str
    file_format : str
    logfile : str
    simple_format : str
    set_logfile(path: str) 'LoggingSetup'
  }
  class Tag {
    name
  }
  class ModuleDef {
    docstring : str
    get_docstring() str
    get_summary() str
  }
  class NodeDef {
    definition : str
    docstring : str
    level : int
    title : str
    get_definition() str
    get_docstring() str
    get_summary() str
    get_title() str
    get_toc_elem() str
  }
  class NodeLink {
    level : int
    parent : Optional[ASTVisitedNode]
  }
  class ObjVisitor {
    node_lst
    parse(source: str) ast.AST
    visit_ClassDef(node: ast.ClassDef) None
    visit_FunctionDef(node: ast.FunctionDef) None
    visit_Module(node: ast.Module) None
  }
  class ConvMD {
    add_tag(begin_tag: str, end_tag: str) Callable[[F], F]
    colorize_examples() Callable[[F], F]
    dedent() Callable[[F], F]
    html_escape() Callable[[F], F]
    repl_beg_end(begin_regexp: str, end_regexp: str, begin_tag: str, end_tag: str) Callable[[F], F]
    repl_str(old_string: str, new_string: str) Callable[[F], F]
  }
  class DocString2MD {
    get_doc() str
    import_module() ExitStatus
    writedoc() ExitStatus
  }
  class DocString2MDOptions {
    output
    private_def : bool
    toc : bool
    todo
    toml
    uml
  }
  class MyFile {
    exists : bool
    path : Optional[Path]
    status
    absolute() str
    read() str
    resolve() str
    set_path(path: Optional[str]) MyFile
    write(data: str) ExitStatus
  }
  class PytMod {
    module
    node_lst
    pkg_main_docstring
    ismodule() bool
    read() None
  }
  class NamedTuple {
  }
  ExitStatus --|> IntEnum
  IntEnum --|> ReprEnum
  ReprEnum --|> Enum
  Const --|> Enum
  EventMSG --|> NamedTuple
  ExitStatus --|> IntEnum
  LogMessages --|> NamedTuple
  LoggingSetup --|> NamedTuple
  Tag --|> Enum
  ModuleDef --|> NamedTuple
  NodeDef --|> NamedTuple
  NodeLink --|> NamedTuple
  ObjVisitor --|> NodeVisitor
  DocString2MDOptions --|> NamedTuple
  MyFile --|> NamedTuple
  DocString2MDOptions --* DocString2MD : __options
  DocString2MDOptions --* DocString2MD : __options
  EventMSG --* LogMessages : logfile
  EventMSG --* LogMessages : args
  EventMSG --* LogMessages : python
  EventMSG --* LogMessages : dump
  EventMSG --* LogMessages : result
  EventMSG --* LogMessages : elapse_time
  EventMSG --* LogMessages : pytmod
  EventMSG --* LogMessages : pytmod_mod
  EventMSG --* LogMessages : pytmod_script
  EventMSG --* LogMessages : pytmod_extract
  EventMSG --* LogMessages : new_module
  EventMSG --* LogMessages : new_class
  EventMSG --* LogMessages : new_func
  EventMSG --* LogMessages : node_link_analysis_beg
  EventMSG --* LogMessages : node_link_analysis_end
  EventMSG --* LogMessages : unknown_type_of_node
  EventMSG --* LogMessages : io_err
  EventMSG --* LogMessages : file_not_found
  EventMSG --* LogMessages : write_doc
  MyFile --* DocString2MDOptions : toml
  MyFile --* DocString2MDOptions : uml
  MyFile --* DocString2MDOptions : todo
  MyFile --* DocString2MDOptions : output
  ExitStatus --* MyFile : status
  PytMod --* DocString2MD : __my_module
  PytMod --* DocString2MD : __my_module


Objects:

Const()
Tag()
LoggingSetup()
LoggingSetup.set_logfile()
EventMSG()
LogMessages()
ExitStatus()
logger_ast()
logger_ast.func_wrapper()
NodeLink()
ModuleDef()
ModuleDef.get_summary()
ModuleDef.get_docstring()
NodeDef()
NodeDef.get_summary()
NodeDef.get_toc_elem()
NodeDef.get_title()
NodeDef.get_definition()
NodeDef.get_docstring()
ObjVisitor()
ObjVisitor.init()
@Property ObjVisitor.node_lst()
ObjVisitor.parse()
ObjVisitor.__set_level()
ObjVisitor.__get_fullname()
ObjVisitor.__get_docstring()
ObjVisitor.__get_value_from_name()
ObjVisitor.__get_value_from_constant()
ObjVisitor.__get_value_from_num()
ObjVisitor.__get_value_from_str()
ObjVisitor.__get_value_from_attribute()
ObjVisitor.__get_value_from_unary()
ObjVisitor.__get_value_from_list()
ObjVisitor.__get_value_from_subscript()
ObjVisitor.__get_value_from_node()
ObjVisitor.visit_Module()
ObjVisitor.__mod_get_docstring()
ObjVisitor.visit_ClassDef()
ObjVisitor.__cla_get_title()
ObjVisitor.__cla_get_def()
ObjVisitor.__cla_get_inheritance()
ObjVisitor.__cla_get_docstring()
ObjVisitor.visit_FunctionDef()
ObjVisitor.__func_valid_name()
ObjVisitor.__func_get_title()
ObjVisitor.__func_get_def()
ObjVisitor.__func_get_args()
ObjVisitor.__func_get_args_annotation()
ObjVisitor.__func_get_args_default()
ObjVisitor.__func_get_decorator()
ObjVisitor.__func_get_decorator_args()
ObjVisitor.__func_get_return()
ObjVisitor.__func_get_docstring()
check_python()
get_argparser()
run()
ConvMD()
ConvMD.repl_str()
ConvMD.repl_str.tags_decorator()
ConvMD.repl_str.tags_decorator.func_wrapper()
ConvMD.repl_beg_end()
ConvMD.repl_beg_end.tags_decorator()
ConvMD.repl_beg_end.tags_decorator.func_wrapper()
ConvMD.add_tag()
ConvMD.add_tag.tags_decorator()
ConvMD.add_tag.tags_decorator.func_wrapper()
ConvMD.html_escape()
ConvMD.html_escape.tags_decorator()
ConvMD.html_escape.tags_decorator.func_wrapper()
ConvMD.colorize_examples()
ConvMD.colorize_examples.tags_decorator()
ConvMD.colorize_examples.tags_decorator.func_wrapper()
ConvMD.dedent()
ConvMD.dedent.tags_decorator()
ConvMD.dedent.tags_decorator.func_wrapper()
DocString2MDOptions()
DocString2MD()
DocString2MD.init()
DocString2MD.import_module()
DocString2MD.get_doc()
DocString2MD.writedoc()
MyFile()
MyFile.set_path()
MyFile.repr()
MyFile.read()
MyFile.write()
MyFile.resolve()
MyFile.absolute()
define_logfile()
PytMod()
PytMod.init()
@Property PytMod.module()
@Property PytMod.node_lst()
@Property PytMod.pkg_main_docstring()
PytMod.ismodule()
PytMod.read()
PytMod.__get_doc_from_module()
PytMod.__get_module_list()
PytMod.__get_doc_from_pkg()

Const()

class Const(Enum):
Define constants.

Tag()

class Tag(Enum):
Define TAG used to build MD file.

LoggingSetup()

class LoggingSetup(NamedTuple):
Define logging Parameters.

Examples:

>>> my_setup = LoggingSetup()
>>> my_setup.default_level
'INFO'

LoggingSetup.set_logfile()

@classmethod
def LoggingSetup.set_logfile(cls, path: str) -> LoggingSetup:
Define the logfile.

This function create the LoggingSetup object with the log file's path.

Args:
    path: The file's path.

Returns:
    MyFile

Examples:

    >>> a = LoggingSetup.set_logfile('report.log')
    >>> str(a)[0:32]
    "LoggingSetup(logfile='report.log"

EventMSG()

class EventMSG(NamedTuple):
Define Messages with different sev.

Attributes:
    info (str): message for info ("" by default)
    warning (str): message for warning ("" by default)
    error (str): message for error ("" by default)
    debug (str): message for debug ("" by default)

Examples:

    >>> logfile = EventMSG(info="Log file used: %s")
    >>> logfile.info
    'Log file used: %s'

LogMessages()

class LogMessages(NamedTuple):
Set standard logging messages.

ExitStatus()

class ExitStatus(IntEnum):
Define Exit status.

logger_ast()

def logger_ast(func: F) -> F:
Use it to decorate AST Navigator Class.

This function decorate an AST function and use the logging to track
the activity.

Args:
    func: F (Callable[..., Any])

Returns:
    F (Callable[..., Any])

logger_ast.func_wrapper()

@wraps(func)
def logger_ast.func_wrapper(*args: Any, **kwargs: Any) -> Any:
None

NodeLink()

class NodeLink(NamedTuple):
Use a NamedTuple to link a node with his parent Node.

Attributes:
    level (int): level in the module
    parent (NodeType): parent

ModuleDef()

class ModuleDef(NamedTuple):
Define a module with this NamedTuple.

Examples:

    >>> mydocstring = "Title:"
    >>> module = ModuleDef(docstring=mydocstring)
    >>> module
    ModuleDef(docstring='Title:')
    >>> module.get_summary()
    '# Title:'

ModuleDef.get_summary()

def ModuleDef.get_summary(self) -> str:
Get the module's summary.

Returns:
    str: Summary

ModuleDef.get_docstring()

@ConvMD.dedent()
@ConvMD.repl_beg_end(Tag.BEG_STR, Tag.END_STRH, Tag.END_TITLE)
def ModuleDef.get_docstring(self) -> str:
Generate the module's Docstring with MD Tag.

Returns:
    str: Docstring

NodeDef()

class NodeDef(NamedTuple):
Define a node (class/function) with this NamedTuple.

Attributes:
    title (str): short class/function definition
    definition (str): full class/function definition
    docstring (str): docstring
    level (int): level in the module

NodeDef.get_summary()

def NodeDef.get_summary(self) -> str:
Get the node's summary.

Returns:
    str

NodeDef.get_toc_elem()

def NodeDef.get_toc_elem(self) -> str:
Get the node's TOC entry.

Returns:
    str

NodeDef.get_title()

def NodeDef.get_title(self) -> str:
Get the node's title.

Returns:
    str

NodeDef.get_definition()

@ConvMD.add_tag(Tag.BEG_PY, Tag.BEG_END_CO)
def NodeDef.get_definition(self) -> str:
Get the node's TOC entry.

Returns:
    str

NodeDef.get_docstring()

@ConvMD.repl_beg_end(Tag.BEG_STR, Tag.END_STRH, Tag.BEG_B, Tag.END_BH)
@ConvMD.colorize_examples()
@ConvMD.add_tag(Tag.CR, Tag.CR)
def NodeDef.get_docstring(self) -> str:
Get the node's Docstring with MD Tag.

Returns:
    str: Docstring

ObjVisitor()

class ObjVisitor(ast.NodeVisitor):
Define the AST NodeVisitor.

This Class is an ast.NodeVisitor class and allow us to parse
code tree.
All methods are called according to node type.
We define other private method in order to manage string format.
We use decorator to keep a clean code without MD Tag.

ObjVisitor(module_docstring=True|False)
    module_docstring: true => retrieve the module docstring
    This parameter is usefull to use the first docstring module
    in a package.

Examples:

    >>> from docstring2md.file import MyFile
    >>> import pathlib
    >>> module = str(pathlib.Path(__file__).resolve())
    >>> source = MyFile.set_path(module)
    >>> # init
    >>> doc = ObjVisitor(module_docstring=False)
    >>> # provide source, generate the tree and use visit mechanism
    >>> doc.visit(doc.parse(source.read()))
    >>> result = doc.node_lst
    >>> result[0].title
    'logger_ast()'
    >>> result[0].get_toc_elem()
    '[logger_ast()](#logger_ast)<br />'
    >>> result[0].definition
    'def logger_ast(func: F) -> F:'

ObjVisitor.init()

def ObjVisitor.__init__(self, module_docstring: bool = False, private_def: bool = False) -> None:
Init the AST analysis.

Args:
    module_docstring (bool): get module docstring
    private_def (bool): get private functions

@Property ObjVisitor.node_lst()

@property
def ObjVisitor.node_lst(self) -> NodeListType:
Get the node list.

ObjVisitor.parse()

@staticmethod
def ObjVisitor.parse(source: str) -> ast.AST:
Parse the source code and build the tree.

Args:
    source (str): source code

Returns:
    AST tree

ObjVisitor.__set_level()

@logger_ast
def ObjVisitor.__set_level(self, node: ASTVisitedNode, level: int = 0, parent: Optional[ASTVisitedNode] = None) -> None:
None

ObjVisitor.__get_fullname()

@logger_ast
def ObjVisitor.__get_fullname(self, node: ASTClassFunc) -> str:
None

ObjVisitor.__get_docstring()

@staticmethod
@logger_ast
def ObjVisitor.__get_docstring(node: ASTVisitedNode) -> str:
None

ObjVisitor.__get_value_from_name()

@staticmethod
def ObjVisitor.__get_value_from_name(node: ast.Name) -> str:
None

ObjVisitor.__get_value_from_constant()

@staticmethod
def ObjVisitor.__get_value_from_constant(node: Union[ast.Constant, ast.NameConstant]) -> str:
None

ObjVisitor.__get_value_from_num()

@staticmethod
def ObjVisitor.__get_value_from_num(node: ast.Num) -> str:
None

ObjVisitor.__get_value_from_str()

@staticmethod
def ObjVisitor.__get_value_from_str(node: ast.Str) -> str:
None

ObjVisitor.__get_value_from_attribute()

def ObjVisitor.__get_value_from_attribute(self, node: ast.Attribute) -> str:
None

ObjVisitor.__get_value_from_unary()

@staticmethod
def ObjVisitor.__get_value_from_unary(node: ast.UnaryOp) -> str:
None

ObjVisitor.__get_value_from_list()

def ObjVisitor.__get_value_from_list(self, node: ast.List) -> str:
None

ObjVisitor.__get_value_from_subscript()

def ObjVisitor.__get_value_from_subscript(self, node: ast.Subscript) -> str:
None

ObjVisitor.__get_value_from_node()

@logger_ast
def ObjVisitor.__get_value_from_node(self, node: Union[ast.Name, ast.Constant, ast.NameConstant, ast.Num, ast.Str, ast.Attribute, ast.Subscript, ast.UnaryOp, ast.List]) -> str:
None

ObjVisitor.visit_Module()

@logger_ast
def ObjVisitor.visit_Module(self, node: ast.Module) -> None:
Visit a module.

This function is automatically called by AST mechanism when the
current node is a module and add a ModuleDef obj in self.node_lst.

Args:
    node (ast.AST): current node

Returns:
    None

ObjVisitor.__mod_get_docstring()

def ObjVisitor.__mod_get_docstring(self, node: ast.Module) -> str:
None

ObjVisitor.visit_ClassDef()

@logger_ast
def ObjVisitor.visit_ClassDef(self, node: ast.ClassDef) -> None:
Visit a Class.

This function is automatically called by AST mechanism when the
current node is a class and add a NodeDef obj in self.node_lst.

Args:
    node (ast.ClassDef): current node

Returns:
    None

ObjVisitor.__cla_get_title()

@logger_ast
def ObjVisitor.__cla_get_title(self, node: ast.ClassDef) -> str:
None

ObjVisitor.__cla_get_def()

@logger_ast
def ObjVisitor.__cla_get_def(self, node: ast.ClassDef) -> str:
None

ObjVisitor.__cla_get_inheritance()

@logger_ast
def ObjVisitor.__cla_get_inheritance(self, node: ast.ClassDef) -> str:
None

ObjVisitor.__cla_get_docstring()

@logger_ast
def ObjVisitor.__cla_get_docstring(self, node: ast.ClassDef) -> str:
None

ObjVisitor.visit_FunctionDef()

@logger_ast
def ObjVisitor.visit_FunctionDef(self, node: ast.FunctionDef) -> None:
Visit Function.

This function is automatically called by AST mechanism when the
current node is a function and add a NodeDef obj in self.node_lst.

Args:
    node (ast.FunctionDef): current node

Returns:
    None

ObjVisitor.__func_valid_name()

@logger_ast
def ObjVisitor.__func_valid_name(self, node: ast.FunctionDef) -> bool:
None

ObjVisitor.__func_get_title()

@logger_ast
def ObjVisitor.__func_get_title(self, node: ast.FunctionDef) -> str:
None

ObjVisitor.__func_get_def()

@logger_ast
def ObjVisitor.__func_get_def(self, node: ast.FunctionDef) -> str:
None

ObjVisitor.__func_get_args()

@logger_ast
def ObjVisitor.__func_get_args(self, node: ast.FunctionDef) -> str:
None

ObjVisitor.__func_get_args_annotation()

@logger_ast
def ObjVisitor.__func_get_args_annotation(self, node: ast.arg) -> str:
None

ObjVisitor.__func_get_args_default()

@logger_ast
def ObjVisitor.__func_get_args_default(self, node: ast.FunctionDef) -> list[str]:
None

ObjVisitor.__func_get_decorator()

@logger_ast
def ObjVisitor.__func_get_decorator(self, node: ast.FunctionDef) -> list[str]:
None

ObjVisitor.__func_get_decorator_args()

@logger_ast
def ObjVisitor.__func_get_decorator_args(self, node: ast.Call) -> str:
None

ObjVisitor.__func_get_return()

@logger_ast
def ObjVisitor.__func_get_return(self, node: ast.FunctionDef) -> str:
None

ObjVisitor.__func_get_docstring()

@logger_ast
def ObjVisitor.__func_get_docstring(self, node: ast.FunctionDef) -> str:
None

check_python()

def check_python() -> bool:
Check python version.

This function check Python version, log the result and return a status
True/False.

Returns:
    True if successful, False otherwise.

get_argparser()

def get_argparser() -> argparse.ArgumentParser:
Define the argument parser.

This function define the argument parser and return it.

Returns:
    ArgumentParser

Examples:

    >>> a = get_argparser()
    >>> type(a)
    <class 'argparse.ArgumentParser'>

run()

def run() -> ExitStatus:
Manage options and analyse modules.

Called by the CLI runner, manage options to analyse the module.
It exits 0 on success, and >0 if an error occurs.

Returns:
    int: status
    return EX_OK: 0 -> success
    return EX_CONFIG: 78 -> config error
    return EX_OSFILE: 72 -> Module not found
    return EX_CANTCREAT: 73 -> can't create the file
    return EX_IOERR: 74 -> write error

ConvMD()

class ConvMD():
Prepare MD string.

ConvMD.repl_str()

@staticmethod
def ConvMD.repl_str(old_string: str, new_string: str) -> Callable[[F], F]:
Search & replace a string by another string.

Args:
    old_string (str): string to search
    new_string (str): new string

Returns:
    Callable[[F], F]

Examples:

    >>> from docstring2md.convmd import ConvMD
    >>> @ConvMD.repl_str("docstring", "is ok !")
    ... def return_test() -> str:
    ...     return "my function docstring"
    >>> print(return_test())
    my function is ok !
ConvMD.repl_str.tags_decorator()
def ConvMD.repl_str.tags_decorator(func: F) -> F:
Decorate.

ConvMD.repl_str.tags_decorator.func_wrapper()
@wraps(func)
def ConvMD.repl_str.tags_decorator.func_wrapper(*args: Any, **kwargs: Any) -> Any:
Wrapp.

ConvMD.repl_beg_end()

@staticmethod
def ConvMD.repl_beg_end(begin_regexp: str, end_regexp: str, begin_tag: str, end_tag: str) -> Callable[[F], F]:
Replace the beginning and the end.

Args:
    begin_regexp (str)
    end_regexp (str)
    begin_tag (str)
    end_tag (str)

Returns:
    decorated function

Examples:

    >>> # All new lines must be provided with a specific tag
    >>> # > 'Line' <br />
    >>> from docstring2md.convmd import ConvMD
    >>> @ConvMD.repl_beg_end("^", "$", ">", "<br />")
    ... def return_test() -> str:
    ...     return "my function docstring"
    >>> print(return_test())
    >my function docstring<br />
ConvMD.repl_beg_end.tags_decorator()
def ConvMD.repl_beg_end.tags_decorator(func: F) -> F:
Decorate.

ConvMD.repl_beg_end.tags_decorator.func_wrapper()
@wraps(func)
def ConvMD.repl_beg_end.tags_decorator.func_wrapper(*args: Any, **kwargs: Any) -> Any:
Wrapp.

ConvMD.add_tag()

@staticmethod
def ConvMD.add_tag(begin_tag: str, end_tag: str) -> Callable[[F], F]:
Add a tag in a string.

Args:
    begin_tag (str)
    end_tag (str)

Returns:
    decorated function

Examples:

    >>> # ('__', '__') => __ TXT __
    >>> from docstring2md.convmd import ConvMD
    >>> @ConvMD.add_tag("__", "__")
    ... def return_test() -> str:
    ...     return "test"
    >>> print(return_test())
    __test__
ConvMD.add_tag.tags_decorator()
def ConvMD.add_tag.tags_decorator(func: F) -> F:
Decorate.

ConvMD.add_tag.tags_decorator.func_wrapper()
@wraps(func)
def ConvMD.add_tag.tags_decorator.func_wrapper(*args: Any, **kwargs: Any) -> Any:
Wrapp.

ConvMD.html_escape()

@staticmethod
def ConvMD.html_escape() -> Callable[[F], F]:
Escape the HTML Tag.

Returns:
    decorated function

ConvMD.html_escape.tags_decorator()
def ConvMD.html_escape.tags_decorator(func: F) -> F:
Decorate.

ConvMD.html_escape.tags_decorator.func_wrapper()
@wraps(func)
def ConvMD.html_escape.tags_decorator.func_wrapper(*args: Any, **kwargs: Any) -> Any:
Wrapp.

ConvMD.colorize_examples()

@staticmethod
def ConvMD.colorize_examples() -> Callable[[F], F]:
Colorize python example.

Returns:
    decorated function

ConvMD.colorize_examples.tags_decorator()
def ConvMD.colorize_examples.tags_decorator(func: F) -> F:
Decorate.

ConvMD.colorize_examples.tags_decorator.func_wrapper()
@wraps(func)
def ConvMD.colorize_examples.tags_decorator.func_wrapper(*args: Any, **kwargs: Any) -> Any:
Wrapp.

ConvMD.dedent()

@staticmethod
def ConvMD.dedent() -> Callable[[F], F]:
Deindent text.

Returns:
    decorated function

ConvMD.dedent.tags_decorator()
def ConvMD.dedent.tags_decorator(func: F) -> F:
Decorate.

ConvMD.dedent.tags_decorator.func_wrapper()
@wraps(func)
def ConvMD.dedent.tags_decorator.func_wrapper(*args: Any, **kwargs: Any) -> Any:
Wrapp.

DocString2MDOptions()

class DocString2MDOptions(NamedTuple):
Define the DocString2MD options.

Attributes:
    toml (MyFile): MyFile.set_path(/path/to/toml/file.toml)
    uml (MyFile): MyFile.set_path(/path/to/mermaid/file.mmd)
    todo (MyFile): MyFile.set_path(/path/to/todo/file.md)
    output (MyFile): MyFile.set_path(/path/to/output/file) (README.md)
    toc (bool): True -> get a table of content
    private_def (bool): True -> get private function

DocString2MD()

class DocString2MD():
Export Google docstring to MD File.

Examples:

    >>> options: DocString2MDOptions = DocString2MDOptions(
    ...         toml=MyFile.set_path(None),
    ...         uml=MyFile.set_path(None),
    ...         output=MyFile.set_path(None),
    ...         todo=MyFile.set_path(None),
    ...         toc=False,
    ...         private_def=False)
    >>> doc = DocString2MD("oups", options)
    >>> doc.import_module()
    <ExitStatus.EX_OSFILE: 72>
    >>> doc = DocString2MD("docstring2md", options)
    >>> doc.import_module()
    <ExitStatus.EX_OK: 0>
    >>> result = doc.get_doc()
    >>> result = result.split("\n")
    >>> result[0]
    '# docstring2md:'

DocString2MD.init()

def DocString2MD.__init__(self, module_name: str, options: DocString2MDOptions) -> None:
Init the obj.

This function define default attributes.

Args:
    module_name (str): /path/to/module/ or 

DocString2MD.import_module()

def DocString2MD.import_module(self) -> ExitStatus:
Import the module.

It exits 0 on success, and >0 if an error occurs.

Returns:
    int: status
    return EX_OK: 0 -> success
    return EX_OSFILE: 72 -> Module not found

DocString2MD.get_doc()

def DocString2MD.get_doc(self) -> str:
Return the documentation.

Returns:
    str: doc

DocString2MD.writedoc()

def DocString2MD.writedoc(self) -> ExitStatus:
Write the doc - screen or files.

It exits 0 on success, and >0 if an error occurs.

args:
    None

Returns:
    int: status
    return EX_OK: 0 -> success
    return EX_CANTCREAT: 73 -> can't create the file
    return EX_IOERR: 74 -> write error

MyFile()

class MyFile(NamedTuple):
Describe a file with a NamedTuple.

@classmethod is used to init the objects correctly.

Notes:
    The objective is to define a file with only one NamedTuple.
    The NamedTuple will be created by the set_path function to
    define the path.

Examples:

    >>> data_file = MyFile.set_path("lorem")
    >>> data_file.status
    <ExitStatus.EX_OSFILE: 72>
    >>> fstab = MyFile.set_path("/etc/fstab")
    >>> fstab.path.stem
    'fstab'
    >>> fstab
    MyFile(path=PosixPath(...), exists=False, status=72)
    >>> fstab.absolute()
    '/etc/fstab'
    >>> # pathlib to run the test everywhere
    >>> import pathlib
    >>> path = str(pathlib.Path(__file__).resolve().parent) + "/"
    >>> lic = MyFile.set_path(f"{path}../../LICENSE")
    >>> lic.path.stem
    'LICENSE'
    >>> lic.exists
    True
    >>> result = lic.read()
    >>> result = result.split("\n")
    >>> result[0]
    '                    GNU GENERAL PUBLIC LICENSE'

MyFile.set_path()

@classmethod
def MyFile.set_path(cls, path: Optional[str]) -> MyFile:
Set path and create the object.

if path is None        -> status = ExitStatus.EX_CANTCREAT
if path exists         -> status = ExitStatus.EX_OK
If path does not exist -> status = ExitStatus.EX_OSFILE

Args:
    path: The file's path.

Returns:
    MyFile or None

MyFile.repr()

def MyFile.__repr__(self) -> str:
Get the repr.

MyFile.read()

def MyFile.read(self) -> str:
Read the file.

Returns:
    str: Text if successful else ""

MyFile.write()

def MyFile.write(self, data: str) -> ExitStatus:
Write data in the file.

Returns:
    int: status
    return EX_OK: 0 -> success
    return EX_CANTCREAT: 73 -> can't create the file
    return EX_IOERR: 74 -> write error

MyFile.resolve()

def MyFile.resolve(self) -> str:
Get the resolved path.

Returns:
    str

MyFile.absolute()

def MyFile.absolute(self) -> str:
Get the absolute path.

Returns:
    str

define_logfile()

def define_logfile(path: str) -> None:
Define the logfile.

This function set up the log to push log events in the report file.

Args:
    path:str    /path/to/logfile
Returns:
    None

PytMod()

class PytMod():
Manage module analysis.

Object in order to extract Python functions, class....

Examples:

    >>> mod = PytMod("oups...")
    >>> mod.read()
    Traceback (most recent call last):
    ...
    ModuleNotFoundError: No module named 'oups'
    >>> mod = PytMod("json")
    >>> mod.read()
    >>> print(mod.node_lst[0].definition)
    def dump(obj, fp, **kw):
    >>> mod = PytMod(__file__)
    >>> mod.read()
    >>> print(mod.node_lst[0].docstring)
    Docstring2md: mod.
    ...
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    >>> mod = PytMod('docstring2md')
    >>> mod.read()
    >>> print(mod.node_lst[0].definition)
    class Const(Enum):

PytMod.init()

def PytMod.__init__(self, module_name: str, private_def: bool = False) -> None:
Init the object.

Args:
    module_name (str): module name
    private_def (bool): extract private def

@Property PytMod.module()

@property
def PytMod.module(self) -> str:
Get the module name.

module name (str):
    modulename
    /path/to/the/mod
    ./path/to/the/mod

@Property PytMod.node_lst()

@property
def PytMod.node_lst(self) -> NodeListType:
Get the docstrings.

Returns:
            str: Docstring

@Property PytMod.pkg_main_docstring()

@property
def PytMod.pkg_main_docstring(self) -> NodeListType:
Get the main docstring.

Returns:
    str: Main docstring

PytMod.ismodule()

def PytMod.ismodule(self) -> bool:
Check the module.

If module name is a module file => True
Else if the module name is a package => False

Returns:
    bool: It exits True on success, and False otherwise.

PytMod.read()

def PytMod.read(self) -> None:
Read the module.

Reads all files and store the result.

Returns:
    None

PytMod.__get_doc_from_module()

def PytMod.__get_doc_from_module(self, module: str, module_docstring: bool = False) -> NodeListType:
None

PytMod.__get_module_list()

def PytMod.__get_module_list(self, package: str) -> list[str]:
None

PytMod.__get_doc_from_pkg()

def PytMod.__get_doc_from_pkg(self, package: str) -> NodeListType:
None