Skip to content

Commit 32e0990

Browse files
authored
[TST] Add automatic doc checking for general functions. (pyjanitor-devs#684)
* Add automatic doc checking for general functions. Testing it out for now, will generalize this to the rest of the functions later. * Fix escape sequence * flake8 fix * Ignore data description in autodoc checks * add skipqcs * deepsource fixes * general skipqc * fix up script * Removed pyprojroot This was added unintentionally * Docstring consistency change * Added check-autodoc to test_patterns in deepsource
1 parent d97eb1b commit 32e0990

File tree

3 files changed

+80
-1
lines changed

3 files changed

+80
-1
lines changed

.azure-pipelines/templates/run-tests.yml

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ steps:
1111
$(activate.command) pyjanitor-dev
1212
pytest
1313
displayName: 'Run all pyjanitor tests.'
14+
- script: |
15+
$(activate.command) pyjanitor-dev
16+
python scripts/check-autodoc.py
17+
displayName: 'Check that all general functions have been added to docs.'
1418
- script: |
1519
$(activate.command) pyjanitor-dev
1620
bash <(curl -s https://codecov.io/bash) -t c4aaeb6c-be8f-44b2-a529-6871f3537261

.deepsource.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ version = 1
22

33
test_patterns = [
44
"tests/**",
5-
"test_*.py"
5+
"test_*.py",
6+
"scripts/check-autodoc.py",
67
]
78

89
[[analyzers]]

scripts/check-autodoc.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
"""
2+
Author: Eric J. Ma, borrowing code from Samuel Oranyeli.
3+
This Python script checks the docs pages for functions
4+
that have not been added to the "General Functions" API docs.
5+
6+
Only the "general_functions.rst" needs the checks,
7+
as the others are auto-populated.
8+
This situation simply evolved out of how the docs are structured,
9+
I am not sure exactly how it turned out this way. :)
10+
"""
11+
12+
import re
13+
from pathlib import Path
14+
from typing import List, Tuple
15+
16+
17+
def extract_function_names(
18+
test_folder: Path, exclude_names: List[str]
19+
) -> List[str]: # skipqc
20+
"""Extract function names from the list of functions."""
21+
function_names = [] # skipqc
22+
for name in test_folder.iterdir():
23+
if not name.is_dir() and path_does_not_contain(name, exclude_names):
24+
function_names.append(name.stem.split("_", 1)[-1].strip())
25+
return function_names
26+
27+
28+
def extract_documented_functions(docs: Path) -> List[str]: # skipqc
29+
"""Extract documented functions from docs page."""
30+
pattern = re.compile(r"\s{4}[a-zA-Z_]+")
31+
32+
# get the names in the general_functions page
33+
with docs.open() as doc:
34+
doc_functions = [ # skipqc
35+
pattern.search(line).group().strip()
36+
for line in doc
37+
if pattern.search(line)
38+
]
39+
return doc_functions
40+
41+
42+
def path_does_not_contain(path: Path, names: List[str]) -> bool:
43+
"""Check if path does not contain a list of names."""
44+
for name in names:
45+
if name in str(path):
46+
return False
47+
return True
48+
49+
50+
def extract_folder_names(test_dir: Path) -> Tuple[Path, str]:
51+
"""Extract folder names.
52+
53+
This function could be used later.
54+
"""
55+
# folder_names = []
56+
for name in test_dir.iterdir():
57+
if name.is_dir() and path_does_not_contain(
58+
name, ["__pycache__", "test_data", "data_description"]
59+
):
60+
module_name = str(name).split("/")[-1]
61+
yield Path(name), module_name
62+
63+
64+
test_folder = Path("./tests/functions")
65+
exclude_names = ["__pycache__", "test_data", "data_description"]
66+
function_names = extract_function_names(test_folder, exclude_names)
67+
docs = Path("./docs/reference/general_functions.rst")
68+
doc_functions = extract_documented_functions(docs)
69+
missing_funcs = set(function_names).difference(doc_functions)
70+
71+
if len(missing_funcs) > 0:
72+
raise Exception(
73+
f"The following functions have not yet been added: {missing_funcs}"
74+
)

0 commit comments

Comments
 (0)