Skip to content

Commit a819b80

Browse files
authored
Add ability to skip private functions (#32)
* Add ability to skip private functions Closes #31 * Make sure skip_private doesn't also skip magic functions * Change flag * Update coverage.py * Add test for skipping private * Add logging * Update test trunder and quadrunder should both also fall under the magic/mangling category * Update coverage.py * Update cli.py * Update private_undocumented.py * Reorganize test files * Reorganize part 2 * Update README.md
1 parent 906e023 commit a819b80

File tree

5 files changed

+45
-1
lines changed

5 files changed

+45
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ docstr-coverage some_project/src
5858

5959
- _--skipmagic, -m_ - Ignore all magic methods (like `__init__`, and `__str__`)
6060
- _--skipfiledoc, -f_ - Ignore module docstrings (at the top of files)
61+
- _--skip-private, -P_ - Ignore private functions (starting with a single underscore)
6162
- _--exclude=\<regex\>, -e \<regex\>_ - Filepath pattern to exclude from analysis
6263
_ To exclude the contents of a virtual environment `env` and your `tests` directory, run:
6364
<br>```\$ docstr-coverage some_project/ -e "env/_|tests/\*"```
@@ -91,7 +92,7 @@ my_coverage = get_docstring_coverage(['some_dir/file_0.py', 'some_dir/file_1.py'
9192
##### Arguments
9293

9394
- Required arg: `filenames` \<list of string filenames\>
94-
- Optional kwargs: `skip_magic` \<bool\>, `skip_file_docstring` \<bool\>, `verbose` \<int (0-3)\> \* For more info on `get_docstring_coverage` and its parameters, please see its [documentation](https://docstr-coverage.readthedocs.io/en/latest/api_essentials.html#get-docstring-coverage)
95+
- Optional kwargs: `skip_magic` \<bool\>, `skip_file_docstring` \<bool\>, `skip_private` \<bool\>, `verbose` \<int (0-3)\> \* For more info on `get_docstring_coverage` and its parameters, please see its [documentation](https://docstr-coverage.readthedocs.io/en/latest/api_essentials.html#get-docstring-coverage)
9596

9697
##### Results
9798

docstr_coverage/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ def parse_ignore_names_file(ignore_names_file: str) -> tuple:
148148
help="Ignore docstrings of class definitions",
149149
show_default=True,
150150
)
151+
@click.option(
152+
"-P",
153+
"--skip-private",
154+
type=bool,
155+
is_flag=True,
156+
default=False,
157+
help="Ignore docstrings of functions starting with a single underscore",
158+
show_default=True,
159+
)
151160
@click.option(
152161
"-l",
153162
"--followlinks",
@@ -225,6 +234,7 @@ def execute(paths, **kwargs):
225234
skip_file_docstring=kwargs["skip_file_docstring"],
226235
skip_init=kwargs["skip_init"],
227236
skip_class_def=kwargs["skip_class_def"],
237+
skip_private=kwargs["skip_private"],
228238
verbose=kwargs["verbose"],
229239
ignore_names=ignore_names,
230240
)

docstr_coverage/coverage.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ def get_docstring_coverage(
8686
skip_file_docstring: bool = False,
8787
skip_init: bool = False,
8888
skip_class_def: bool = False,
89+
skip_private: bool = False,
8990
verbose: int = 0,
9091
ignore_names: Tuple[List[str], ...] = (),
9192
):
@@ -107,6 +108,9 @@ def get_docstring_coverage(
107108
skip_class_def: Boolean, default=False
108109
If True, skips class definitions and does not include them in the report.
109110
If this is True, the class's methods will still be checked
111+
skip_private: Boolean, default=False
112+
If True, skips function definitions beginning with a single underscore and does
113+
not include them in the report.
110114
verbose: Int in [0, 1, 2, 3], default=0
111115
0) No printing.
112116
1) Print total stats only.
@@ -211,6 +215,8 @@ def print_docstring(base, node, filename, ignore_names=()):
211215
docs_needed -= 1
212216
elif skip_class_def and "_" not in name and (name[0] == name[0].upper()):
213217
docs_needed -= 1
218+
elif skip_private and name.startswith("_") and not name.startswith("__"):
219+
docs_needed -= 1
214220
elif ignore_names and do_ignore_node(filename, base, name, ignore_names):
215221
docs_needed -= 1
216222
else:
@@ -318,6 +324,8 @@ def print_docstring(base, node, filename, ignore_names=()):
318324
postfix += " (skipped __init__ methods)"
319325
if skip_class_def:
320326
postfix += " (skipped class definitions)"
327+
if skip_private:
328+
postfix += " (skipped private methods)"
321329

322330
log("\n", 2)
323331

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Test file for undocumented private methods."""
2+
3+
4+
def _foo():
5+
pass
6+
7+
8+
def __dunder():
9+
pass

tests/test_coverage.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
PARTLY_DOCUMENTED_FILE_PATH = os.path.join(SAMPLES_DIRECTORY, "partly_documented_file.py")
1212
SOME_CODE_NO_DOCS_FILE_PATH = os.path.join(SAMPLES_DIRECTORY, "some_code_no_docs.py")
1313

14+
SAMPLES_C_DIRECTORY = os.path.join("tests", "extra_samples")
15+
PRIVATE_NO_DOCS_PATH = os.path.join(SAMPLES_C_DIRECTORY, "private_undocumented.py")
16+
1417

1518
def test_should_report_for_an_empty_file():
1619
file_results, total_results = get_docstring_coverage([EMPTY_FILE_PATH])
@@ -205,3 +208,16 @@ def test_logging_partially_documented_file(caplog, expected, verbose, ignore_nam
205208
)
206209

207210
assert caplog.messages == expected
211+
212+
213+
def test_skip_private():
214+
file_results, total_results = get_docstring_coverage([PRIVATE_NO_DOCS_PATH], skip_private=True)
215+
assert file_results[PRIVATE_NO_DOCS_PATH] == {
216+
"missing": ["__dunder"],
217+
"module_doc": True,
218+
"missing_count": 1,
219+
"needed_count": 2,
220+
"coverage": 50.0,
221+
"empty": False,
222+
}
223+
assert total_results == {"missing_count": 1, "needed_count": 2, "coverage": 50.0}

0 commit comments

Comments
 (0)