From ecdd733d38f8358b0d2f6bff5a2ed61adbe25adc Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 3 Dec 2024 15:22:01 +0100 Subject: [PATCH 01/15] Start writing docs --- doc/source/index.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 doc/source/index.rst diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 0000000..a3f4ada --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,19 @@ +docstub's documentation +======================= + +**Date**: |today|, **Version**: |version| + +Welcome! `docstub` is a command-line tool to generate `Python`_ stub files +(i.e., PYI files) from type descriptions found in `numpydoc`_ style docstrings. + +`numpy`_, `scipy`_, and the scikits follow a common convention for docstrings +that provides for consistency, while also allowing toolchains such as +`numpydoc`_ to produce well-formatted reference guides. + +Our project follows the `SciPy code of conduct`_. + +.. _numpy: https://numpy.org +.. _numpydoc: https://numpydoc.readthedocs.io +.. _Python: https://www.python.org +.. _scipy: https://docs.scipy.org +.. _Scipy code of conduct: https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst From 60eead1fb73c72e9ecb18abb5aa8a2ff489a563d Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 14 Jan 2025 15:57:18 +0100 Subject: [PATCH 02/15] Start with just a Markdown file --- doc/{source/index.rst => index.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename doc/{source/index.rst => index.md} (100%) diff --git a/doc/source/index.rst b/doc/index.md similarity index 100% rename from doc/source/index.rst rename to doc/index.md From 50758a74ddc116d2d003f90c5cffe4548f199868 Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 14 Jan 2025 16:08:11 +0100 Subject: [PATCH 03/15] Convert RST file to MD --- doc/index.md | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/doc/index.md b/doc/index.md index a3f4ada..fc79d48 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,19 +1,17 @@ -docstub's documentation -======================= +# docstub's documentation -**Date**: |today|, **Version**: |version| +**Date**: , **Version**: -Welcome! `docstub` is a command-line tool to generate `Python`_ stub files -(i.e., PYI files) from type descriptions found in `numpydoc`_ style docstrings. +Welcome! [docstub]{.title-ref} is a command-line tool to generate +[Python](https://www.python.org) stub files (i.e., PYI files) from type +descriptions found in [numpydoc](https://numpydoc.readthedocs.io) style +docstrings. -`numpy`_, `scipy`_, and the scikits follow a common convention for docstrings -that provides for consistency, while also allowing toolchains such as -`numpydoc`_ to produce well-formatted reference guides. +[numpy](https://numpy.org), [scipy](https://docs.scipy.org), and the +scikits follow a common convention for docstrings that provides for +consistency, while also allowing toolchains such as +[numpydoc](https://numpydoc.readthedocs.io) to produce well-formatted +reference guides. -Our project follows the `SciPy code of conduct`_. - -.. _numpy: https://numpy.org -.. _numpydoc: https://numpydoc.readthedocs.io -.. _Python: https://www.python.org -.. _scipy: https://docs.scipy.org -.. _Scipy code of conduct: https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst +Our project follows the [SciPy code of +conduct](https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst). From bd09212e73cc8b1eca459f7bb9d893f381249340 Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 14 Jan 2025 16:08:38 +0100 Subject: [PATCH 04/15] Drop date for now --- doc/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.md b/doc/index.md index fc79d48..91ce220 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,6 +1,6 @@ # docstub's documentation -**Date**: , **Version**: +**Version**: Welcome! [docstub]{.title-ref} is a command-line tool to generate [Python](https://www.python.org) stub files (i.e., PYI files) from type From 699c509f3552cb85287e0158b11d520be21c3996 Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 14 Jan 2025 17:16:16 +0100 Subject: [PATCH 05/15] Explain the gist of docstub --- doc/index.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/doc/index.md b/doc/index.md index 91ce220..a4793ba 100644 --- a/doc/index.md +++ b/doc/index.md @@ -15,3 +15,47 @@ reference guides. Our project follows the [SciPy code of conduct](https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst). + +## Basics + +Consider a function written as follows: + +```py +def example_metric(image0, image1, sigma=1.0, method='standard'): + """Pretend to calculate a local metric between two images. + + Parameters + ---------- + image0 : array-like + First image. + image1 : array_like + Second image. + sigma : float + Sigma parameter. + method : {'standard', 'modified'}, optional, default = 'standard' + The method to use for calculating the metric. + + Returns + ------- + met : ndarray of dtype float + """ + pass +``` + +Feeding this input to docstub results in the following output: + +```py +def example_metric( + image0: ArrayLike, + image1: ArrayLike, + sigma: float = ..., + method: Literal["standard", "modified"] = ..., +) -> NDArray[float] +``` + +As you can see, it is a typed function signature, where types are read from +the well-enough written docstring. + +In practice, you run the docstub command on a .py file and get a corresponding +.pyi file containing the same imports, the same variables, with classes and +functions replaced with their respective typed signatures. From f3a34943e46303b4fab761c763379a6d55f9f3cd Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 14 Jan 2025 17:22:33 +0100 Subject: [PATCH 06/15] Update intro --- doc/index.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/index.md b/doc/index.md index a4793ba..3aa7494 100644 --- a/doc/index.md +++ b/doc/index.md @@ -4,11 +4,12 @@ Welcome! [docstub]{.title-ref} is a command-line tool to generate [Python](https://www.python.org) stub files (i.e., PYI files) from type -descriptions found in [numpydoc](https://numpydoc.readthedocs.io) style +descriptions found in [numpydoc](https://numpydoc.readthedocs.io)-style docstrings. -[numpy](https://numpy.org), [scipy](https://docs.scipy.org), and the -scikits follow a common convention for docstrings that provides for +[numpy](https://numpy.org), [scipy](https://docs.scipy.org), +[scikit-image](https://scikit-image.org/), and others +follow a common convention for docstrings that provides for consistency, while also allowing toolchains such as [numpydoc](https://numpydoc.readthedocs.io) to produce well-formatted reference guides. From 8c3a470cb0b712b928cf394a3393d710eda33c0d Mon Sep 17 00:00:00 2001 From: Marianne Corvellec Date: Tue, 14 Jan 2025 17:23:00 +0100 Subject: [PATCH 07/15] Draw from structure by NumPy docs --- doc/index.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/doc/index.md b/doc/index.md index 3aa7494..657e380 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,8 +1,10 @@ -# docstub's documentation +# docstub user guide **Version**: -Welcome! [docstub]{.title-ref} is a command-line tool to generate +## What is docstub? + +[docstub]{.title-ref} is a command-line tool to generate [Python](https://www.python.org) stub files (i.e., PYI files) from type descriptions found in [numpydoc](https://numpydoc.readthedocs.io)-style docstrings. @@ -17,7 +19,14 @@ reference guides. Our project follows the [SciPy code of conduct](https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst). -## Basics +## Installation + +To install docstub, you need Python 3.10, 3.11, or 3.12. +We recommend that you install docstub with `pip`: + + pip install 'docstub [optional] @ git+https://github.com/scientific-python/docstub' + +## Fundamentals and usage Consider a function written as follows: From 06c034171227b99635d7b4beee21b086dce73ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Wed, 12 Mar 2025 13:59:07 +0100 Subject: [PATCH 08/15] Update doc/index.md Co-authored-by: Marianne Corvellec --- doc/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.md b/doc/index.md index 657e380..7b86d5c 100644 --- a/doc/index.md +++ b/doc/index.md @@ -64,7 +64,7 @@ def example_metric( ``` As you can see, it is a typed function signature, where types are read from -the well-enough written docstring. +the (well-enough) written docstring. In practice, you run the docstub command on a .py file and get a corresponding .pyi file containing the same imports, the same variables, with classes and From 1005981e421fc153578f6df718abda3cfee842bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Thu, 8 May 2025 19:19:35 +0200 Subject: [PATCH 09/15] Add command line reference to doc/ and ensure it's correctness with a test. --- doc/command_line_reference.md | 27 +++++++++++++++++++++++++++ tests/test_doc.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 doc/command_line_reference.md create mode 100644 tests/test_doc.py diff --git a/doc/command_line_reference.md b/doc/command_line_reference.md new file mode 100644 index 0000000..25e3383 --- /dev/null +++ b/doc/command_line_reference.md @@ -0,0 +1,27 @@ +# Command line reference + +Running +``` +docstub --help +``` +will print + + + + +```plain +Usage: docstub [OPTIONS] ROOT_PATH + + Generate Python stub files from docstrings. + +Options: + --version Show the version and exit. + -o, --out-dir DIRECTORY Set output directory explicitly. + --config FILE Set configuration file explicitly. + --group-errors Group errors by type and content. Will delay + showing errors until all files have been processed. + -v, --verbose Log more details. + -h, --help Show this message and exit. +``` + + diff --git a/tests/test_doc.py b/tests/test_doc.py new file mode 100644 index 0000000..ee5fc41 --- /dev/null +++ b/tests/test_doc.py @@ -0,0 +1,31 @@ +"""Test documentation in doc/.""" + +import re +from pathlib import Path + +import click + +from docstub._cli import main + +PROJECT_ROOT = Path(__file__).parent.parent + + +def test_command_line_help(): + ctx = click.Context(main, info_name="docstub") + expected_help = f""" + +```plain +{main.get_help(ctx)} +``` + +""" + md_file = PROJECT_ROOT / "doc/command_line_reference.md" + with md_file.open("r") as io: + md_content = io.read() + + regex = r"(.*)" + match = re.findall(regex, md_content, flags=re.DOTALL) + assert len(match) == 1 + + actual_help = match[0] + assert actual_help == expected_help From 3a2c3d49cf6fc390f6248b4e2e6dee3e78723755 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Thu, 8 May 2025 19:20:18 +0200 Subject: [PATCH 10/15] Draft typing_reference.md --- doc/typing_reference.md | 94 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 doc/typing_reference.md diff --git a/doc/typing_reference.md b/doc/typing_reference.md new file mode 100644 index 0000000..5fc8f02 --- /dev/null +++ b/doc/typing_reference.md @@ -0,0 +1,94 @@ +# Typing with docstub + +> [!NOTE] +> This document is work in progress and might be incomplete. + + +## Docstring annotation syntax + +The basic structure of to describe the type of a symbol is as follows: +``` +name : type_description (, optional) (, extra_info) +``` +- `name` might be the name of a parameter or attribute. + But typing names in other sections like "Returns" or "Yields" is also supported. +- `type_description` +- `optional` +- `extra_info` + + +[Grammar reference](../src/docstub/doctype.lark) + + +### Or + +| Docstring type | Python type annotation | +|----------------|------------------------| +| `X or Y` | `X \| Y` | + + +### Containers + +| Docstring type | Python type annotation | +|----------------------------|------------------------| +| `CONTAINER of X` | `CONTAINER[X]` | +| `CONTAINER of (X \| Y)` | `CONTAINER[X \| Y]` | +| `CONTAINER of (X, Y, ...)` | `CONTAINER[X, Y, ...]` | + + +### Shape and dtype syntax for arrays + +`array` and `ndarray`, and `array-like` and `array_like` can be used interchange-ably. + +| Docstring type | Python type annotation | +|-----------------------------|------------------------| +| `array of DTYPE` | `ndarray[DTYPE]` | +| `ndarray of dtype DTYPE` | `ndarray[DTYPE]` | +| `array-like of DTYPE` | `ArrayLike[DTYPE]` | +| `array_like of dtype DTYPE` | `ArrayLike[DTYPE]` | + +> [!NOTE] +> Noting the **shape** of an array in the docstring is supported. +> However, typing is not yet possible and the shape doesn't impact the resulting annotation. + +| Docstring type | Python type annotation | +|--------------------------|------------------------| +| `(3,) array of DTYPE` | `ndarray[DTYPE]` | +| `(X, Y) array of DTYPE` | `ndarray[DTYPE]` | +| `([P,] M, N) array-like` | `ArrayLike` | +| `(M, ...) ndarray` | `ArrayLike` | + + +### Literals + +| Docstring type | Python type annotation | +|---------------------|----------------------------| +| `{1, "string", .2}` | `Literal[1, "string", .2]` | +| `{X}` | `Literal[X]` | + + +### Sphinx-like reference + +| Docstring type | Python type annotation | +|-------------------|------------------------| +| ``:ref:`X` `` | `X` | +| ``:class:`Y.X` `` | `Y.X` | + +Can be used in any context where a qualified name can be used. + + +## Special cases + +### Disable docstub with comment directive + +```python +class Foo: + """Docstring.""" + + # docstub: off + a: int = None + b: str = "" + c: int = None + b: str = "" + # docstub: on +``` From 89048756d6c92d79a8d8efd669e1db49e2fe3c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Thu, 8 May 2025 19:42:26 +0200 Subject: [PATCH 11/15] Draft user guide Copy over the structure from index.md and extend it. --- doc/index.md | 71 ----------------------------------- doc/user_guide.md | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 71 deletions(-) delete mode 100644 doc/index.md create mode 100644 doc/user_guide.md diff --git a/doc/index.md b/doc/index.md deleted file mode 100644 index 7b86d5c..0000000 --- a/doc/index.md +++ /dev/null @@ -1,71 +0,0 @@ -# docstub user guide - -**Version**: - -## What is docstub? - -[docstub]{.title-ref} is a command-line tool to generate -[Python](https://www.python.org) stub files (i.e., PYI files) from type -descriptions found in [numpydoc](https://numpydoc.readthedocs.io)-style -docstrings. - -[numpy](https://numpy.org), [scipy](https://docs.scipy.org), -[scikit-image](https://scikit-image.org/), and others -follow a common convention for docstrings that provides for -consistency, while also allowing toolchains such as -[numpydoc](https://numpydoc.readthedocs.io) to produce well-formatted -reference guides. - -Our project follows the [SciPy code of -conduct](https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst). - -## Installation - -To install docstub, you need Python 3.10, 3.11, or 3.12. -We recommend that you install docstub with `pip`: - - pip install 'docstub [optional] @ git+https://github.com/scientific-python/docstub' - -## Fundamentals and usage - -Consider a function written as follows: - -```py -def example_metric(image0, image1, sigma=1.0, method='standard'): - """Pretend to calculate a local metric between two images. - - Parameters - ---------- - image0 : array-like - First image. - image1 : array_like - Second image. - sigma : float - Sigma parameter. - method : {'standard', 'modified'}, optional, default = 'standard' - The method to use for calculating the metric. - - Returns - ------- - met : ndarray of dtype float - """ - pass -``` - -Feeding this input to docstub results in the following output: - -```py -def example_metric( - image0: ArrayLike, - image1: ArrayLike, - sigma: float = ..., - method: Literal["standard", "modified"] = ..., -) -> NDArray[float] -``` - -As you can see, it is a typed function signature, where types are read from -the (well-enough) written docstring. - -In practice, you run the docstub command on a .py file and get a corresponding -.pyi file containing the same imports, the same variables, with classes and -functions replaced with their respective typed signatures. diff --git a/doc/user_guide.md b/doc/user_guide.md new file mode 100644 index 0000000..f8ff37c --- /dev/null +++ b/doc/user_guide.md @@ -0,0 +1,96 @@ +# User guide + +> [!NOTE] +> In early development! +> Expect to encounter bugs, missing features, and fatal errors. + + +## Installation + +While a docstub package is already available on PyPI, we recommend trying out docstub by installing directly from GitHub with + +```shell +pip install 'docstub [optional] @ git+https://github.com/scientific-python/docstub' +``` + +If you want to pin to a certain commit you can append `@COMMIT_SHA` to the repo URL above. + + +## Getting started + +Consider a simple example with the following documented function + +```python +# src/example.py + +def example_metric(image, *, mask=None, sigma=1.0, method='standard'): + """Pretend to calculate a local metric between two images. + + Parameters + ---------- + image : array-like + First image. + mask : array of dtype uint8, optional + Second image. + sigma : float or Iterable of float, optional + Sigma value for each dimension in `image`. A single value is broadcast + to all dimensions. + method : {'standard', 'modified'}, optional, default = 'standard' + The method to use for calculating the metric. + + Returns + ------- + met : ndarray of dtype float + """ + pass +``` + +Feeding this input to docstub with + +```shell +docstub simple_script.py +``` + +will create `example.pyi` in the same directory + +```python +# File generated with docstub + +from collections.abc import Iterable +from typing import Literal + +import numpy as np +from numpy.typing import ArrayLike, NDArray + +def example_metric( + image: ArrayLike, + *, + mask: NDArray[np.uint8] | None = ..., + sigma: float | Iterable[float] = ..., + method: Literal["standard", "modified"] = ... +) -> NDArray[float]: ... +``` + +There are several interesting things to note here: + +- Many existing conventions that the scientific Python ecosystem uses, will work out of the box. + In this case, docstub knew how to translate `array-like`, `array of dtype uint8` into a valid type annotation in the stub file. + +- In a similar manner, `or` can be used as a "natural language" alternative to `|`. + +- Optional arguments that default to `None` are recognized and a `| None` is appended automatically if the type doesn't include it already. + +- Common container types such as `Iterable` can be used and a necessary import will be added automatically. + + +## Importing types + + +## Adding your own aliases for docstring descriptions + + +## Adopting docstub gradually + +`--group-errors` + +`--allow-errors` From 1701b7947c2913e3e2526e5ef6c80ccb8c5794aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Thu, 8 May 2025 19:42:56 +0200 Subject: [PATCH 12/15] Tweak README and point to user guide --- README.md | 53 +++++++++++++++++++---------------------------------- 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 6eb71e9..b19a0ae 100644 --- a/README.md +++ b/README.md @@ -2,53 +2,38 @@ > [!NOTE] > In early development! +> Expect to encounter bugs, missing features, and fatal errors. -A command line tool to generate Python stub files (PYI) from type descriptions -in NumPyDoc style docstrings. +docstub is a command-line tool to generate [Python](https://www.python.org) stub files (i.e., PYI files) from type descriptions found in [numpydoc](https://numpydoc.readthedocs.io)-style docstrings. +Many packages in the scientific Python ecosystem already describe expected parameter and return types in their docstrings. +Docstub aims to take advantage of these and help with the adoption of type annotations. +It does so by supporting widely used readable conventions such as `array of dtype` or `iterable of int` which it translates into valid type annotations. -## Installation -To try out docstub, for now, we recommend installing docstub directly from this -repo: +## Installation & getting started -```shell -pip install 'docstub [optional] @ git+https://github.com/scientific-python/docstub' -``` +Please refer to the [user guide](doc/user_guide.md) to get started with docstub. -## Usage & configuration - -```shell -cd examples/ -docstub example_pkg/ -``` -will create stub files for `example_pkg/` in `examples/example_pkg-stubs/`. -For now, refer to `docstub --help` for more. - - -### Declare imports and synonyms - -Types in docstrings can and are used without having to import them. However, -when docstub creates stub files from these docstrings it actually needs to -know how to import those unknown types. - -> [!TIP] -> docstub already knows about types in Python's `typing` or `collections.abc` -> modules. That means you can just use types like `Literal` or `Sequence`. - -While docstub is smart enough to find some types via static analysis of -definitions in the given source directory, it must be told about other types -for now. To do so, refer to the syntax and comments in the -`default_config.toml`. +## Contributing +The best way you can help and contribute right now is by trying docstub out! +Feedback to what features might still be missing or where it breaks for you would be greatly appreciated. +Pointers to where the documentation is confusing and unclear. -## Contributing +Since docstub is still in early development there isn't an official contribution guide yet. +Docstubs features and API is still being heavily extended and the internal structure is still somewhat in flux. +That said, if that only entices you, feel free to open a PR. +But please do check in with an issue before you do so. -TBD +Our project follows the [SciPy code of +conduct](https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst). ## Acknowledgements Thanks to [docs2stubs](https://github.com/gramster/docs2stubs) by which this project was heavily inspired and influenced. + +And thanks to CZI for supporting this work with an [EOSS grant](https://chanzuckerberg.com/eoss/proposals/from-library-to-protocol-scikit-image-as-an-api-reference/). From c9414f540960277034f476ffabc7d83297e875ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Thu, 8 May 2025 20:06:41 +0200 Subject: [PATCH 13/15] Test example.py and example.pyi blocks in user guide --- doc/command_line_reference.md | 2 +- doc/user_guide.md | 10 +++++- tests/test_doc.py | 58 +++++++++++++++++++++++++++++------ 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/doc/command_line_reference.md b/doc/command_line_reference.md index 25e3383..23208ca 100644 --- a/doc/command_line_reference.md +++ b/doc/command_line_reference.md @@ -6,7 +6,7 @@ docstub --help ``` will print - + ```plain diff --git a/doc/user_guide.md b/doc/user_guide.md index f8ff37c..4fd2945 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -20,8 +20,11 @@ If you want to pin to a certain commit you can append `@COMMIT_SHA` to the repo Consider a simple example with the following documented function + + + ```python -# src/example.py +# example.py def example_metric(image, *, mask=None, sigma=1.0, method='standard'): """Pretend to calculate a local metric between two images. @@ -45,6 +48,8 @@ def example_metric(image, *, mask=None, sigma=1.0, method='standard'): pass ``` + + Feeding this input to docstub with ```shell @@ -53,6 +58,8 @@ docstub simple_script.py will create `example.pyi` in the same directory + + ```python # File generated with docstub @@ -70,6 +77,7 @@ def example_metric( method: Literal["standard", "modified"] = ... ) -> NDArray[float]: ... ``` + There are several interesting things to note here: diff --git a/tests/test_doc.py b/tests/test_doc.py index ee5fc41..5418381 100644 --- a/tests/test_doc.py +++ b/tests/test_doc.py @@ -5,27 +5,67 @@ import click -from docstub._cli import main +from docstub._cli import main as docstub_main PROJECT_ROOT = Path(__file__).parent.parent +def test_getting_started_example(tmp_path): + # Load user guide + md_file = PROJECT_ROOT / "doc/user_guide.md" + with md_file.open("r") as io: + md_content = io.read() + + # Extract code block for example.py + regex_py = ( + r"" + r"\n```python\n(.*)\n```\n" + r"" + ) + matches_py = re.findall(regex_py, md_content, flags=re.DOTALL) + assert len(matches_py) == 1 + py_source = matches_py[0] + + # Create example.py and run docstub on it + py_file = tmp_path / "example.py" + with py_file.open("x") as io: + io.write(py_source) + docstub_main([str(py_file)], standalone_mode=False) + + # Load created PYI file, this is what we expect to find in the user guide's + # code block for example.pyi + pyi_file = py_file.with_suffix(".pyi") + assert pyi_file.is_file() + with pyi_file.open("r") as io: + expected_pyi = io.read().strip() + + # Extract code block for example.pyi from guide + regex_pyi = ( + r"" + r"\n```python\n(.*)\n```\n" + r"" + ) + matches_pyi = re.findall(regex_pyi, md_content, flags=re.DOTALL) + assert len(matches_pyi) == 1 + actual_pyi = matches_pyi[0].strip() + + assert expected_pyi == actual_pyi + + def test_command_line_help(): - ctx = click.Context(main, info_name="docstub") + ctx = click.Context(docstub_main, info_name="docstub") expected_help = f""" - ```plain -{main.get_help(ctx)} +{docstub_main.get_help(ctx)} ``` - -""" +""".strip() md_file = PROJECT_ROOT / "doc/command_line_reference.md" with md_file.open("r") as io: md_content = io.read() regex = r"(.*)" - match = re.findall(regex, md_content, flags=re.DOTALL) - assert len(match) == 1 + matches = re.findall(regex, md_content, flags=re.DOTALL) + assert len(matches) == 1 - actual_help = match[0] + actual_help = matches[0].strip() assert actual_help == expected_help From 8f3d831a051800c8d27d973d52ec0a618e2d35ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Fri, 9 May 2025 14:07:30 +0200 Subject: [PATCH 14/15] Correctly point to Scientific Python's CoC That one is automatically assigned to the repo from the GitHub org. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b19a0ae..7c695c0 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,7 @@ Docstubs features and API is still being heavily extended and the internal struc That said, if that only entices you, feel free to open a PR. But please do check in with an issue before you do so. -Our project follows the [SciPy code of -conduct](https://github.com/scipy/scipy/blob/master/doc/source/dev/conduct/code_of_conduct.rst). +Our project follows the [Scientific Python's Code of Conduct](https://scientific-python.org/code_of_conduct/). ## Acknowledgements From bb431c2ed8ee0c9153ed361d64a9c0c0561069b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gr=C3=BCter?= Date: Fri, 9 May 2025 14:14:48 +0200 Subject: [PATCH 15/15] Update command line reference --- doc/command_line_reference.md | 27 ++++++++++++++++++--------- doc/user_guide.md | 2 ++ tests/test_doc.py | 4 ++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/doc/command_line_reference.md b/doc/command_line_reference.md index 23208ca..c6e641f 100644 --- a/doc/command_line_reference.md +++ b/doc/command_line_reference.md @@ -10,18 +10,27 @@ will print ```plain -Usage: docstub [OPTIONS] ROOT_PATH +Usage: docstub [OPTIONS] PACKAGE_PATH - Generate Python stub files from docstrings. + Generate Python stub files with type annotations from docstrings. + + Given a path `PACKAGE_PATH` to a Python package, generate stub files for it. + Type descriptions in docstrings will be used to fill in missing inline type + annotations or to override them. Options: - --version Show the version and exit. - -o, --out-dir DIRECTORY Set output directory explicitly. - --config FILE Set configuration file explicitly. - --group-errors Group errors by type and content. Will delay - showing errors until all files have been processed. - -v, --verbose Log more details. - -h, --help Show this message and exit. + --version Show the version and exit. + -o, --out-dir PATH Set output directory explicitly. Otherwise, stubs are + generated inplace. + --config PATH Set configuration file explicitly. + --group-errors Group identical errors together and list where they + occured. Will delay showing errors until all files have + been processed. Otherwise, simply report errors as the + occur. + --allow-errors INT Allow this many or fewer errors. If docstub reports + more, exit with error code '1'. [default: 0; x>=0] + -v, --verbose Print more details (repeatable). + -h, --help Show this message and exit. ``` diff --git a/doc/user_guide.md b/doc/user_guide.md index 4fd2945..d96c990 100644 --- a/doc/user_guide.md +++ b/doc/user_guide.md @@ -60,6 +60,7 @@ will create `example.pyi` in the same directory + ```python # File generated with docstub @@ -77,6 +78,7 @@ def example_metric( method: Literal["standard", "modified"] = ... ) -> NDArray[float]: ... ``` + There are several interesting things to note here: diff --git a/tests/test_doc.py b/tests/test_doc.py index 5418381..26fc35f 100644 --- a/tests/test_doc.py +++ b/tests/test_doc.py @@ -19,7 +19,7 @@ def test_getting_started_example(tmp_path): # Extract code block for example.py regex_py = ( r"" - r"\n```python\n(.*)\n```\n" + r"\n+```python(.*)```\n+" r"" ) matches_py = re.findall(regex_py, md_content, flags=re.DOTALL) @@ -42,7 +42,7 @@ def test_getting_started_example(tmp_path): # Extract code block for example.pyi from guide regex_pyi = ( r"" - r"\n```python\n(.*)\n```\n" + r"\n+```python(.*)```\n+" r"" ) matches_pyi = re.findall(regex_pyi, md_content, flags=re.DOTALL)