Skip to content

Commit a7a53f1

Browse files
committed
Merge remote-tracking branch 'upstream/master' into feat/tqdm-progress
2 parents b019082 + b99b23e commit a7a53f1

File tree

15 files changed

+241
-31
lines changed

15 files changed

+241
-31
lines changed

.github/workflows/python-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
strategy:
3131
matrix:
3232
os: [macos-latest, windows-latest, ubuntu-latest]
33-
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
33+
python-version: [3.6, 3.7, 3.8, 3.9, "3.10"]
3434

3535
steps:
3636
- uses: actions/checkout@v2

.pre-commit-config.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
repos:
22
- repo: https://github.com/ambv/black
3-
rev: 21.5b2
3+
rev: 22.3.0
44
hooks:
55
- id: black
66
language_version: python3.7
77
- repo: https://gitlab.com/pycqa/flake8
8-
rev: 3.9.2
8+
rev: 4.0.1
99
hooks:
1010
- id: flake8
11+
- repo: https://github.com/pycqa/isort
12+
rev: 5.10.1
13+
hooks:
14+
- id: isort
15+
name: isort (python)

CHANGELOG.md

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@
44
...
55

66

7+
<a name="2.2.0"></a>
8+
## [2.2.0] (2022-03-17)
9+
10+
### Features
11+
- Add `--skip-property` flag to ignore methods with the `@property` decorator. [#86] by [MiWeiss].
12+
- Add `--include-setter` flag to check methods with the `@setter` decorator. [#86] by [MiWeiss].
13+
- Add `--include-deleter` flag to check methods with the `@deleter` decorator. [#86] by [MiWeiss].
14+
15+
16+
<a name="2.1.1"></a>
17+
## [2.1.1] (2021-07-02)
18+
19+
### Bug Fixes
20+
- Fix inconsistent pre-commit hook behavior. [#84] by [killthekitten].
21+
- This was caused by the hook being run on different sets of files
22+
- If you are experiencing issues with the pre-commit hook, please ensure that you have
23+
properly set the `paths` argument in your config file
24+
25+
### Changes
26+
- Don't report on fully-documented files by default. [#85] by [MiWeiss].
27+
- The new verbosity level of 4 will include fully-documented files in the report
28+
29+
730
<a name="2.1.0"></a>
831
## [2.1.0] (2021-06-25)
932

@@ -124,7 +147,9 @@
124147
* Initial release
125148

126149

127-
[Unreleased]: https://github.com/HunterMcGushion/docstr_coverage/compare/v2.1.0...HEAD
150+
[Unreleased]: https://github.com/HunterMcGushion/docstr_coverage/compare/v2.2.0...HEAD
151+
[2.2.0]: https://github.com/HunterMcGushion/docstr_coverage/compare/v2.1.1...v2.2.0
152+
[2.1.1]: https://github.com/HunterMcGushion/docstr_coverage/compare/v2.1.0...v2.1.1
128153
[2.1.0]: https://github.com/HunterMcGushion/docstr_coverage/compare/v2.0.1...v2.1.0
129154
[2.0.1]: https://github.com/HunterMcGushion/docstr_coverage/compare/v2.0.0...v2.0.1
130155
[2.0.0]: https://github.com/HunterMcGushion/docstr_coverage/compare/v1.4.0...v2.0.0
@@ -170,4 +195,7 @@
170195
[#57]: https://github.com/HunterMcGushion/docstr_coverage/pull/57
171196
[#67]: https://github.com/HunterMcGushion/docstr_coverage/pull/67
172197
[#78]: https://github.com/HunterMcGushion/docstr_coverage/pull/78
173-
[#82]: https://github.com/HunterMcGushion/docstr_coverage/pull/82
198+
[#82]: https://github.com/HunterMcGushion/docstr_coverage/pull/82
199+
[#84]: https://github.com/HunterMcGushion/docstr_coverage/pull/84
200+
[#85]: https://github.com/HunterMcGushion/docstr_coverage/pull/85
201+
[#86]: https://github.com/HunterMcGushion/docstr_coverage/pull/86

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ docstr-coverage some_project/src
7878
- _--skip-file-doc, -f_ - Ignore module docstrings (at the top of files)
7979
- _--skip-private, -P_ - Ignore private functions (starting with a single underscore)
8080
- _--skip-class-def, -c_ - Ignore docstrings of class definitions
81+
- _--skip-property, -sp_ - Ignore functions with `@property` decorator
82+
- _--include-setter, -is_ - Include functions with `@setter` decorator (skipped by default)
83+
- _--include-deleter, -idel_ - Include functions with `@deleter` decorator (skipped by default)
8184
- _--accept-empty, -a_ - Exit with code 0 if no Python files are found (default: exit code 1)
8285
- _--exclude=\<regex\>, -e \<regex\>_ - Filepath pattern to exclude from analysis
8386
- To exclude the contents of a virtual environment `env` and your `tests` directory, run:
@@ -117,7 +120,7 @@ paths: # list or string
117120
- docstr_coverage
118121
badge: docs # Path
119122
exclude: .*/test # regex
120-
verbose: 1 # int (0-3)
123+
verbose: 3 # int (0-4)
121124
skip_magic: True # Boolean
122125
skip_file_doc: True # Boolean
123126
skip_init: True # Boolean
@@ -157,9 +160,9 @@ Note that `docstr-coverage` can not parse
157160
dynamically added documentation (e.g. through class extension).
158161
Thus, some of your code which deliberately has no docstring might be counted as uncovered.
159162

160-
You can override this by adding either ```#docstr_coverage:inherited```
163+
You can override this by adding either ```# docstr-coverage:inherited```
161164
(intended for use if a docstring is provided in the corresponding superclass method)
162-
or a generic excuse with a reason, like ```#docstr_coverage:excused `My probably bad excuse` ```.
165+
or a generic excuse with a reason, like ```# docstr-coverage:excused `My probably bad excuse` ```.
163166
These have to be stated right above any class or function definition
164167
(or above the functions annotations, if applicable).
165168
Such class or function would then be counted as if they had a docstring.
@@ -183,7 +186,7 @@ and configuring the `paths` section of the [`.docstr.yaml` config](#config-file)
183186
```yaml
184187
repos:
185188
- repo: https://github.com/HunterMcGushion/docstr_coverage
186-
rev: v2.1.0 # most recent docstr-coverage release or commit sha
189+
rev: v2.2.0 # most recent docstr-coverage release or commit sha
187190
hooks:
188191
- id: docstr-coverage
189192
args: ["--verbose", "2"] # override the .docstr.yaml to see less output

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
author = "Hunter McGushion"
2222

2323
version = "" # The short X.Y version
24-
release = "2.1.0" # The full version, including alpha/beta/rc tags
24+
release = "2.2.0" # The full version, including alpha/beta/rc tags
2525

2626
##################################################
2727
# General Configuration

docstr_coverage/cli.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,21 @@ def _assert_valid_key_value(k, v):
180180
@click.option("-f", "--skip-file-doc", is_flag=True, help="Ignore module docstrings")
181181
@click.option("-i", "--skip-init", is_flag=True, help="Ignore docstrings of `__init__` methods")
182182
@click.option("-c", "--skip-class-def", is_flag=True, help="Ignore docstrings of class definitions")
183+
@click.option(
184+
"-sp", "--skip-property", is_flag=True, help="Ignore functions with @property decorator"
185+
)
186+
@click.option(
187+
"-is",
188+
"--include-setter",
189+
is_flag=True,
190+
help="Include functions with @setter decorator (default: ignored)",
191+
)
192+
@click.option(
193+
"-idel",
194+
"--include-deleter",
195+
is_flag=True,
196+
help="Include functions with @deleter decorator (default: ignored)",
197+
)
183198
@click.option(
184199
"-P",
185200
"--skip-private",
@@ -319,6 +334,9 @@ def execute(paths, **kwargs):
319334
skip_init=kwargs["skip_init"],
320335
skip_class_def=kwargs["skip_class_def"],
321336
skip_private=kwargs["skip_private"],
337+
skip_property=kwargs["skip_property"],
338+
skip_setter=not kwargs["include_setter"],
339+
skip_deleter=not kwargs["include_deleter"],
322340
ignore_names=ignore_names,
323341
)
324342

docstr_coverage/coverage.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import os
44
import re
55
from ast import parse
6-
from typing import Dict, List, Tuple
6+
from typing import Dict, List, Optional, Tuple
77

88
from tqdm import tqdm
99

@@ -63,7 +63,7 @@ def _do_ignore_node(filename: str, base_name: str, node_name: str, ignore_names:
6363

6464
def _analyze_docstrings_on_node(
6565
base: str,
66-
node: Tuple[str, bool, List],
66+
node: Tuple[str, bool, Optional[str], List],
6767
filename,
6868
ignore_config: IgnoreConfig,
6969
result_storage: File,
@@ -88,7 +88,7 @@ def _analyze_docstrings_on_node(
8888
The result-collection.File instance on which the observed
8989
docstring presence should be stored."""
9090

91-
name, has_doc, child_nodes = node
91+
name, has_doc, decorator, child_nodes = node
9292

9393
##################################################
9494
# Check Current Node
@@ -113,6 +113,12 @@ def _analyze_docstrings_on_node(
113113
filename, base, name, ignore_config.ignore_names
114114
):
115115
ignore_reason = "matching ignore pattern"
116+
elif ignore_config.skip_deleter and decorator == "@deleter":
117+
ignore_reason = "skip-deleter set to True"
118+
elif ignore_config.skip_property and decorator == "@property":
119+
ignore_reason = "skip-property set to True"
120+
elif ignore_config.skip_setter and decorator == "@setter":
121+
ignore_reason = "skip-setter set to True"
116122

117123
# Set Result
118124
node_identifier = str(base) + str(name)

docstr_coverage/ignore_config.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,34 @@ class IgnoreConfig:
77

88
def __init__(
99
self,
10+
ignore_names: Tuple[List[str], ...] = (),
1011
skip_magic: bool = False,
1112
skip_file_docstring: bool = False,
1213
skip_init: bool = False,
1314
skip_class_def: bool = False,
1415
skip_private: bool = False,
15-
ignore_names: Tuple[List[str], ...] = (),
16+
skip_property: bool = False,
17+
skip_setter: bool = True,
18+
skip_deleter: bool = True,
1619
):
20+
self._ignore_names = ignore_names
1721
self._skip_magic = skip_magic
1822
self._skip_file_docstring = skip_file_docstring
1923
self._skip_init = skip_init
2024
self._skip_class_def = skip_class_def
2125
self._skip_private = skip_private
22-
self._ignore_names = ignore_names
26+
self._skip_property = skip_property
27+
self._skip_setter = skip_setter
28+
self._skip_deleter = skip_deleter
29+
30+
@property
31+
def ignore_names(self):
32+
"""Patterns to ignore when checking documentation. Each list in `ignore_names` defines a
33+
different pattern to be ignored. The first element in each list is the regular expression
34+
for matching filenames. All remaining arguments in each list are regexes for matching names
35+
of functions/classes. A node is ignored if it matches the filename regex and at least one
36+
of the remaining regexes"""
37+
return self._ignore_names
2338

2439
@property
2540
def skip_magic(self):
@@ -45,15 +60,20 @@ def skip_class_def(self):
4560

4661
@property
4762
def skip_private(self):
48-
"""If True, skip function definitions beginning with a single underscore and exclude them
49-
from the report"""
63+
"""If True, skip function definitions beginning with a single underscore."""
5064
return self._skip_private
5165

5266
@property
53-
def ignore_names(self):
54-
"""Patterns to ignore when checking documentation. Each list in `ignore_names` defines a
55-
different pattern to be ignored. The first element in each list is the regular expression
56-
for matching filenames. All remaining arguments in each list are regexes for matching names
57-
of functions/classes. A node is ignored if it matches the filename regex and at least one
58-
of the remaining regexes"""
59-
return self._ignore_names
67+
def skip_property(self):
68+
"""If True, skip nodes with `@property` decorator."""
69+
return self._skip_property
70+
71+
@property
72+
def skip_setter(self):
73+
"""If True, skip nodes with `@setter` decorator."""
74+
return self._skip_setter
75+
76+
@property
77+
def skip_deleter(self):
78+
"""If True, skip nodes with `@deleter` decorator."""
79+
return self._skip_deleter

docstr_coverage/visitor.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import re
33
import tokenize
44
from ast import ClassDef, FunctionDef, Module, NodeVisitor, get_docstring
5+
from typing import Optional
56

67
ACCEPTED_EXCUSE_PATTERNS = (
78
re.compile(r"#\s*docstr-coverage\s*:\s*inherit(ed)?\s*"),
@@ -25,7 +26,7 @@ def visit_Module(self, node: Module):
2526
with module-wide node info."""
2627
has_doc = self._has_docstring(node)
2728
is_empty = not len(node.body)
28-
self.tree.append((has_doc, is_empty, []))
29+
self.tree.append((has_doc, is_empty, None, []))
2930
self.generic_visit(node)
3031

3132
def visit_ClassDef(self, node: ClassDef):
@@ -42,7 +43,8 @@ def _visit_helper(self, node):
4243
also visited"""
4344
self.symbol_count += 1
4445
has_doc = self._has_doc_or_excuse(node)
45-
_node = (node.name, has_doc, [])
46+
relevant_decorator = self._relevant_decorator(node)
47+
_node = (node.name, has_doc, relevant_decorator, [])
4648
self.tree[-1][-1].append(_node)
4749
self.tree.append(_node)
4850
self.generic_visit(node)
@@ -100,3 +102,18 @@ def _has_excuse(self, node):
100102
def _has_docstring(node):
101103
"""Uses ast to check if the passed node contains a non-empty docstring"""
102104
return get_docstring(node) is not None and get_docstring(node).strip() != ""
105+
106+
@staticmethod
107+
def _relevant_decorator(node) -> Optional[str]:
108+
if hasattr(node, "decorator_list"):
109+
for parsed_decorator in node.decorator_list:
110+
if hasattr(parsed_decorator, "id"):
111+
if parsed_decorator.id == "property":
112+
return "@property"
113+
if hasattr(parsed_decorator, "attr"):
114+
if parsed_decorator.attr == "setter":
115+
return "@setter"
116+
if hasattr(parsed_decorator, "attr"):
117+
if parsed_decorator.attr == "deleter":
118+
return "@deleter"
119+
return None

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def readme():
66
return f.read()
77

88

9-
MAJOR, MINOR, MICRO = 2, 1, 0
9+
MAJOR, MINOR, MICRO = 2, 2, 0
1010
__VERSION__ = "{}.{}.{}".format(MAJOR, MINOR, MICRO)
1111

1212
setup(
@@ -27,8 +27,8 @@ def readme():
2727
packages=["docstr_coverage"],
2828
install_requires=["click", "PyYAML", "tqdm==4.63.1"],
2929
extras_require={
30-
"lint": ["flake8==3.9.2", "black==21.5b2", "isort==5.9.0"],
31-
"test": ["pytest==5.4.2", "pytest-mock==3.4.0"],
30+
"lint": ["flake8==4.0.1", "black==22.3.0", "isort==5.10.1"],
31+
"test": ["pytest==6.2.5", "pytest-mock==3.4.0"],
3232
},
3333
include_package_data=True,
3434
zip_safe=False,

0 commit comments

Comments
 (0)