Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4f235d7
pytest workflow
deven367 Nov 4, 2025
9dc6148
tests for `coreforecast`
deven367 Nov 4, 2025
02619ab
append path correctly
deven367 Nov 4, 2025
27ef88e
pytest.ini
deven367 Nov 4, 2025
93ba70e
pyyaml dep
deven367 Nov 4, 2025
c1abeb2
install coreforecast
deven367 Nov 4, 2025
2eff2ce
migrate common logic to conftest
deven367 Nov 4, 2025
1ebdcef
tests for utilsforecast
deven367 Nov 4, 2025
adfca7f
Merge pull request #2 from Nixtla/test-utilsforecast
deven367 Nov 4, 2025
523b8e2
install utilsforecast
deven367 Nov 4, 2025
24ddd6b
revise logic for default options
deven367 Nov 5, 2025
7c257e9
tests for `datasetsforecast`
deven367 Nov 5, 2025
08d3705
make pytest output verbose
deven367 Nov 5, 2025
672b415
clean-up
deven367 Nov 5, 2025
217b416
mark tests as `datasets`
deven367 Nov 5, 2025
7245a94
fix ini file and add marker
deven367 Nov 5, 2025
29ed0c5
skip tests for datasetsforecast for now (unknown issue for now, runs …
deven367 Nov 5, 2025
e07a864
update README with the Notion link
deven367 Nov 10, 2025
2624a94
tests for `hierarchicalforecast`
deven367 Nov 13, 2025
de98655
tests for `statsforecast`
deven367 Nov 13, 2025
eb9ea3e
tests for `mlforecast`
deven367 Nov 13, 2025
7f0c431
tests for `neuralforecast`
deven367 Nov 13, 2025
05bf3e7
install missing deps
deven367 Nov 13, 2025
690eaa3
fix syntax
deven367 Nov 13, 2025
3374c8a
migrate to a clean requirements.txt
deven367 Nov 13, 2025
6ddb2cb
fix tests for hierarchical
deven367 Nov 13, 2025
943773c
fix tests for statsforecast
deven367 Nov 13, 2025
45843cc
add logic to parse additional types of docstrings
deven367 Nov 13, 2025
34b8544
fix tests for datasets
deven367 Nov 13, 2025
153a838
add more tests for hierarchical
deven367 Nov 13, 2025
c7e3898
fix test for `mlforecast`
deven367 Nov 13, 2025
f250e4d
test `datasets` as well
deven367 Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: pytest

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:


jobs:
run-tests:
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v4

- name: Setup python
uses: actions/setup-python@v4
with:
python-version: 3.11
cache: 'pip'

- name: Install dependencies
run: |
pip install -r requirements.txt

- name: Run tests
run: pytest
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# mkdocstring-parser

This repo creates a simple parser for mkdocstrings. The idea is simple, given a `mkdocstrings` signature block, replace it with it rendered markdown in-place
This repo creates a simple parser for mkdocstrings. The idea is simple, given
a `mkdocstrings` signature block, replace it with it rendered markdown in-place.

To view the complete guide on generating Nixtlaverse documentation, click [here](https://www.notion.so/nixtla/Env-Setup-1aa34e7ecc8c804096f7d0915aa4f2d5?source=copy_link#2a334e7ecc8c8006901aed0eb6ebd2f0)

## example

Expand Down
48 changes: 26 additions & 22 deletions parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,37 +82,41 @@ def generate_documentation(self, module_path: str, options: Dict[str, Any]) -> s
except:
pass # Fall back to griffe's detection

# Determine which parser to use based on docstring_style option
docstring_style = options.get("docstring_style", "google")

# Map docstring style to parser function
parser_map = {
"google": griffe.parse_google,
"numpy": griffe.parse_numpy,
"sphinx": griffe.parse_sphinx,
"auto": griffe.parse_auto,
}

parser_func = parser_map.get(docstring_style, griffe.parse_google)

if obj.docstring:
# Force parsing with Google parser to get structured sections
obj.docstring.parsed = griffe.parse_google(obj.docstring)
# Parse with the appropriate parser to get structured sections
obj.docstring.parsed = parser_func(obj.docstring)

# Handle different object types
if hasattr(obj, "members"):
# This is a class or module - parse docstrings for all methods/functions
for member_name, member in obj.members.items():
if member.docstring:
member.docstring.parsed = griffe.parse_google(member.docstring)
member.docstring.parsed = parser_func(member.docstring)

# Create ConfigDict with the options
# Adjust default options based on object type
if hasattr(obj, "kind") and obj.kind.value == "function":
# Configuration for functions
default_options = {
"docstring_section_style": "table",
"heading_level": 3,
"show_root_heading": True,
"show_source": True,
"show_signature": True,
}
else:
default_options = {
"docstring_section_style": "table",
"heading_level": 3,
"show_root_heading": True,
"show_source": True,
}


if hasattr(obj, "kind") and obj.kind.value != "function":
# Configuration for classes and modules
default_options = {
"docstring_section_style": "table",
"heading_level": 3,
"show_root_heading": True,
"show_source": True,
"summary": {"functions": False},
}
default_options["summary"] = {"functions": False}

default_options.update(options)
config = ConfigDict(**default_options)
Expand Down
5 changes: 5 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[pytest]
testpaths = tests
addopts = -vv
markers =
datasets: tests for datasetsforecast
12 changes: 12 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
griffe2md
rich
pyyaml
neuralforecast
mlforecast[dask]
statsforecast
hierarchicalforecast
nixtla
coreforecast
utilsforecast
datasetsforecast
pytest
13 changes: 13 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from parser import MkDocstringsParser

import pytest


@pytest.fixture(scope="module")
def setup_parser():
parser = MkDocstringsParser()
yield parser
51 changes: 51 additions & 0 deletions tests/test_coreforecast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
def test_regular_fn(setup_parser):
parser = setup_parser
regular_fn = """::: coreforecast.differences.num_diffs"""
output = parser.process_markdown(regular_fn)

assert output == """### `num_diffs`

```python
num_diffs(x, max_d=1)
```

Find the optimal number of differences

**Parameters:**

Name | Type | Description | Default
---- | ---- | ----------- | -------
`x` | <code>[ndarray](#numpy.ndarray)</code> | Array with the time series. | *required*
`max_d` | <code>[int](#int)</code> | Maximum number of differences to consider. Defaults to 1. | <code>1</code>

**Returns:**

Name | Type | Description
---- | ---- | -----------
`int` | <code>[int](#int)</code> | Optimal number of differences.
"""

def test_fn_w_decorator(setup_parser):
parser = setup_parser
fn_w_decorator = """::: coreforecast.expanding.expanding_mean"""
output = parser.process_markdown(fn_w_decorator)
assert output == """### `expanding_mean`

```python
expanding_mean(x)
```

Compute the expanding_mean of the input array.

**Parameters:**

Name | Type | Description | Default
---- | ---- | ----------- | -------
`x` | <code>np.ndarray</code> | Input array. | *required*

**Returns:**

Type | Description
---- | -----------
| np.ndarray: Array with the expanding statistic
"""
78 changes: 78 additions & 0 deletions tests/test_datasetsforecast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import pytest


@pytest.mark.datasets
def test_yearly_dataclass(setup_parser):
fn = "::: datasetsforecast.m3.Yearly"
rendered = setup_parser.process_markdown(fn)

assert rendered == """### `Yearly`

```python
Yearly(seasonality=1, horizon=6, freq='Y', sheet_name='M3Year', name='Yearly', n_ts=645)
```

#### `Yearly.freq`

```python
freq: str = 'Y'
```

#### `Yearly.horizon`

```python
horizon: int = 6
```

#### `Yearly.n_ts`

```python
n_ts: int = 645
```

#### `Yearly.name`

```python
name: str = 'Yearly'
```

#### `Yearly.seasonality`

```python
seasonality: int = 1
```

#### `Yearly.sheet_name`

```python
sheet_name: str = 'M3Year'
```
"""

@pytest.mark.datasets
def test_download_file(setup_parser):
fn = """::: datasetsforecast.utils.download_file
handler: python
options:
docstring_style: numpy
heading_level: 3
show_root_heading: true
show_source: true"""
rendered = setup_parser.process_markdown(fn)

assert rendered == """### `download_file`

```python
download_file(directory, source_url, decompress=False)
```

Download data from source_ulr inside directory.

**Parameters:**

Name | Type | Description | Default
---- | ---- | ----------- | -------
`directory` | <code>[str](#str)</code> | Custom directory where data will be downloaded. | *required*
`source_url` | <code>[str](#str)</code> | URL where data is hosted. | *required*
`decompress` | <code>[bool](#bool)</code> | Wheter decompress downloaded file. Default False. | <code>False</code>
"""
Loading