============================================================ DocString: A Class to Format Docstrings for Sphinx and Click ============================================================ The :py:class:`comb_utils.lib.docs.DocString` class is used to format docstrings for `Sphinx `_ API docs and `Click `_ CLI help docs. It's useful when you have multiple functions that should have the same docstring, such as when you have a public API function and a CLI function that call the same underlying code. :code:`DocString` takes an opening docstring, an arg dict, a default dict, a list of returns text, and a list of :py:class:`comb_utils.lib.docs.ErrorDocString` objects. It has three important members that you can use: :api_docstring: Docstring formatted for Sphinx API docs. :cli_docstring: Docstring formatted for Click. :args: Simply the arg dict you pass when you initialize the :code:`DocString` object. The main difference between :code:`api_docstring` and :code:`cli_docstring` is that :code:`cli_docstring` excludes the args block. CLI args help is picked up by Click in the :code:`click.option` decorators' :code:`help` arguments, to which you can pass the values in :code:`args`. Example usage: .. code:: python from comb_utils import DocString, ErrorDocString ADD_EM_DOCSTRING = DocString( opening_docstring="A function to add two numbers.", args={ "a": "The first number. Must be greater than 0.", "b": "The second number. Must be less than 100." }, returns=["The sum of the two numbers."], error_docstrings=[ ErrorDocString( error_type="ValueError", docstring="If `a` is less than 0." ), ErrorDocString( error_type="ValueError", docstring="If `b` is greater than 100." ) ] defaults={ "a": 1, "b": 99 }, ) Now you can use :code:`docstring.api_docstring` in your functions, and :code:`docstring.cli_docstring` and :code:`args` in your Click commands. Using :code:`docstring.api_docstring` in a function: .. code:: python def add_em(a: int = ADD_EM_DOCSTRING.defaults["a"], b: int = ADD_EM_DOCSTRING.defaults["b"]) -> int: if a < 0: raise ValueError("a must be greater than 0.") if b > 100: raise ValueError("b must be less than 100.") return a + b add_em.__doc__ = ADD_EM_DOCSTRING.api_docstring Now your Sphinx API docs will have the correct docstring for :code:`add_em`. Using :code:`docstring.cli_docstring` and :code:`args` in a Click command: .. code:: python import click from my_package import ADD_EM_DOCSTRING, add_em @click.command(help=ADD_EM_DOCSTRING.cli_docstring) @click.option("--a", type=int, help=ADD_EM_DOCSTRING.args["a"]) @click.option("--b", type=int, help=ADD_DOADD_EM_DOCSTRINGCSTRING.args["b"]) def main(a: int, b: int): the_sum = add_em(a=a, b=b) click.echo(the_sum) Now your CLI command help will have a docstring and args that match the function's docstring. Say you created an entry point named :code:`add_em` in your :code:`setup.cfg` file: .. code:: ini [options.entry_points] console_scripts = add_em = my_package.cli.add_em:main Then, when you run :code:`add_em --help`, you'll see the correct help doc: .. code:: bash $ add_em --help Usage: add_em [OPTIONS] A function to add two numbers. Raises: ValueError: If `a` is less than 0. ValueError: If `b` is greater than 100. Returns: The sum of the two numbers. Options: --a INTEGER The first number. Must be greater than 0. --b INTEGER The second number. Must be less than 100. --help Show this message and exit. You can even use the sphinx-click extension's click directive to include the Click help doc within the CLI module itself, and it's not a problem that it's a circular reference. This is useful for keeping the Sphinx' CLI docs in sync with the CLI's help doc. It's not really a feauture of :code:`DocString`, but it's worth mentioning here: .. code:: python __doc__ = """ .. click:: my_package.cli.add_em:main :prog: add_em :nested: full """ import click from my_package import ADD_EM_DOCSTRING, add_em @click.command(help=ADD_EM_DOCSTRING.cli_docstring) @click.option("--a", type=int, help=ADD_EM_DOCSTRING.args["a"]) @click.option("--b", type=int, help=ADD_DOADD_EM_DOCSTRINGCSTRING.args["b"]) def main(a: int, b: int): the_sum = add_em(a=a, b=b) click.echo(the_sum)