Skip to content

Commit

Permalink
Add flag to support google code style
Browse files Browse the repository at this point in the history
  • Loading branch information
econchick committed Apr 7, 2024
1 parent 5461ebc commit f77ef6f
Show file tree
Hide file tree
Showing 26 changed files with 195 additions and 54 deletions.
12 changes: 12 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ Configure within your ``pyproject.toml`` (``interrogate`` will automatically det
exclude = ["setup.py", "docs", "build"]
ignore-regex = ["^get$", "^mock_.*", ".*BaseClass.*"]
ext = []
# possible values: sphinx (default), google
style = sphinx
# possible values: 0 (minimal output), 1 (-v), 2 (-vv)
verbose = 0
quiet = false
Expand Down Expand Up @@ -399,6 +401,8 @@ Or configure within your ``setup.cfg`` (``interrogate`` will automatically detec
exclude = setup.py,docs,build
ignore-regex = ^get$,^mock_.*,.*BaseClass.*
ext = []
; possible values: sphinx (default), google
style = sphinx
; possible values: 0 (minimal output), 1 (-v), 2 (-vv)
verbose = 0
quiet = false
Expand Down Expand Up @@ -539,6 +543,14 @@ To view all options available, run ``interrogate --help``:
`-w/--whitelist-regex` invocations
supported.
--style [sphinx|google] Style of docstrings to honor. Using `google`
will consider a class and its `__init__`
method both covered if there is either a
class-level docstring, or an `__init__`
method docstring, instead of enforcing both.
Mutually exclusive with `-i`/`--ignore-init`
flag. [default: sphinx]
-o, --output FILE Write output to a given FILE. [default:
stdout]
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Added

* `tomli` dependency for Python versions < 3.11, making use of `tomllib` in the standard library with 3.11+ (`#150 <https://github.com/econchick/interrogate/issues/150>`_).
* Support for ``pyi`` file extensions (and leave room for other file extensions to be added, like maybe ``ipynb``).
* Support for Google-style docstrings for class ``__init__`` methods with new ``--style [sphinx|google]`` flag (`#128 <https://github.com/econchick/interrogate/issues/128>`_).

Fixed
^^^^^
Expand Down
7 changes: 7 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ Command Line Options

Regex identifying class, method, and function names to include. Multiple ``-r/--ignore-regex`` invocations supported.

.. option:: --style [sphinx|google]

Style of docstrings to honor. Using ``google`` will consider a class and its ``__init__`` method
both covered if there is either a class-level docstring, or an ``__init__`` method docstring,
instead of enforcing both. Mutually exclusive with ``-i/--ignore-init`` flag.
[default: ``sphinx``]

.. option:: -o, --output FILE

Write output to a given ``FILE``. [default: ``stdout``]
Expand Down
22 changes: 22 additions & 0 deletions src/interrogate/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,18 @@
"Multiple `-w/--whitelist-regex` invocations supported."
),
)
@click.option(
"--style",
type=click.Choice(["sphinx", "google"]),
default="sphinx",
show_default=True,
help=(
"Style of docstrings to honor.\nUsing `google` will consider a class "
"and its `__init__` method both covered if there is either a class-"
"level docstring, or an `__init__` method docstring, instead of "
"enforcing both. Mutually exclusive with `-i`/`--ignore-init` flag."
),
)
@click.option(
"-o",
"--output",
Expand Down Expand Up @@ -323,6 +335,7 @@ def main(ctx, paths, **kwargs):
.. versionadded:: 1.5.0 ``--badge-style``
.. versionadded:: 1.6.0 ``--ignore-overloaded-functions``
.. verisonadded:: 1.7.0 ``--ext``
.. versionadded:: 1.7.0 ``--style=sphinx|google``
.. versionchanged:: 1.3.1 only generate badge if results change from
an existing badge.
Expand All @@ -340,6 +353,14 @@ def main(ctx, paths, **kwargs):
"The `--badge-style` option must be used along with the `-g/"
"--generate-badge option."
)
if kwargs["style"] == "google" and kwargs["ignore_init_method"]:
raise click.BadOptionUsage(
option_name="style",
message=(
"The `--ignore-init-method` flag is mutually exclusive with "
"`--style google`."
),
)
if not paths:
paths = (os.path.abspath(os.getcwd()),)

Expand All @@ -353,6 +374,7 @@ def main(ctx, paths, **kwargs):

conf = config.InterrogateConfig(
color=kwargs["color"],
docstring_style=kwargs["style"],
fail_under=kwargs["fail_under"],
ignore_regex=kwargs["ignore_regex"],
ignore_magic=kwargs["ignore_magic"],
Expand Down
14 changes: 14 additions & 0 deletions src/interrogate/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class InterrogateConfig:
"""Configuration related to interrogating a given codebase.
:param bool color: Highlight verbose output with color.
:param str docstring_style: Style of docstrings to follow. Choices:
"sphinx" (default), "google".
:param fail_under: Fail when coverage % is less than a given amount.
:type fail_under: `int` or `float`
:param str ignore_regex: Regex identifying class, method, and
Expand All @@ -48,7 +50,10 @@ class InterrogateConfig:
functions.
"""

VALID_STYLES = ("sphinx", "google")

color = attr.ib(default=False)
docstring_style = attr.ib(default="sphinx")
fail_under = attr.ib(default=80.0)
ignore_regex = attr.ib(default=False)
ignore_magic = attr.ib(default=False)
Expand All @@ -65,6 +70,15 @@ class InterrogateConfig:
include_regex = attr.ib(default=False)
omit_covered_files = attr.ib(default=False)

@docstring_style.validator
def _check_style(self, attribute, value):
"""Validate selected choice for docstring style"""
if value not in self.VALID_STYLES:
raise ValueError(
f"Invalid `docstring_style` '{value}'. Valid values: "
f"{', '.join(self.VALID_STYLES)}"
)


def find_project_root(srcs):
"""Return a directory containing .git, .hg, or pyproject.toml.
Expand Down
20 changes: 20 additions & 0 deletions src/interrogate/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,23 @@ def _filter_inner_nested(self, nodes):
filtered_nodes = [n for n in filtered_nodes if n not in nested_cls]
return filtered_nodes

def _set_google_style(self, nodes):
"""Apply Google-style docstrings for class coverage.
Update coverage of a class node if its `__init__` method has a
docstring, or an `__init__` method if its class has a docstring.
A class and its `__init__` method are considered covered if either one
contains a docstring. See <https://sphinxcontrib-napoleon.readthedocs.
io/en/latest/example_google.html>`_ for more info and an example.
"""
for node in nodes:
if node.node_type == "FunctionDef" and node.name == "__init__":
if not node.covered and node.parent.covered:
setattr(node, "covered", True)
elif node.covered and not node.parent.covered:
setattr(node.parent, "covered", True)

def _get_file_coverage(self, filename):
"""Get coverage results for a particular file."""
with open(filename, encoding="utf-8") as f:
Expand All @@ -232,6 +249,9 @@ def _get_file_coverage(self, filename):
if self.config.ignore_nested_classes:
filtered_nodes = self._filter_inner_nested(filtered_nodes)

if self.config.docstring_style == "google":
self._set_google_style(filtered_nodes)

results = InterrogateFileResult(
filename=filename,
ignore_module=self.config.ignore_module,
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/fixtures/expected_detailed.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
| Bar.method_bar.InnerBar (L97) | COVERED |
| _SemiprivateClass (L103) | COVERED |
| __PrivateClass (L109) | COVERED |
| InitDocs (L116) | COVERED |
| InitDocs.__init__ (L117) | COVERED |
| ClassDocs (L123) | COVERED |
| ClassDocs.__init__ (L126) | COVERED |
|------------------------------------------------------------------|-----------|
| partial.py (module) | COVERED |
| Foo (L8) | COVERED |
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/fixtures/expected_detailed_no_module.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
| Bar.method_bar.InnerBar (L97) | COVERED |
| _SemiprivateClass (L103) | COVERED |
| __PrivateClass (L109) | COVERED |
| InitDocs (L116) | COVERED |
| InitDocs.__init__ (L117) | COVERED |
| ClassDocs (L123) | COVERED |
| ClassDocs.__init__ (L126) | COVERED |
|------------------------------------------------------------------|-----------|
| partial.py | |
| Foo (L8) | COVERED |
Expand Down
8 changes: 6 additions & 2 deletions tests/functional/fixtures/expected_detailed_single_file.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@
| Bar.method_bar.InnerBar (L97) | COVERED |
| _SemiprivateClass (L103) | COVERED |
| __PrivateClass (L109) | COVERED |
| InitDocs (L116) | COVERED |
| InitDocs.__init__ (L117) | COVERED |
| ClassDocs (L123) | COVERED |
| ClassDocs.__init__ (L126) | COVERED |
|-----------------------------------------------------|------------------------|

----------------------------------- Summary ------------------------------------
| Name | Total | Miss | Cover | Cover% |
|------------------|--------------|-------------|--------------|---------------|
| full.py | 25 | 0 | 25 | 100% |
| full.py | 29 | 0 | 29 | 100% |
|------------------|--------------|-------------|--------------|---------------|
| TOTAL | 25 | 0 | 25 | 100.0% |
| TOTAL | 29 | 0 | 29 | 100.0% |
--------------- RESULT: PASSED (minimum: 80.0%, actual: 100.0%) ----------------
2 changes: 1 addition & 1 deletion tests/functional/fixtures/expected_no_verbosity.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
RESULT: FAILED (minimum: 80.0%, actual: 51.4%)
RESULT: FAILED (minimum: 80.0%, actual: 54.1%)
4 changes: 2 additions & 2 deletions tests/functional/fixtures/expected_summary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
|------------------------------------------|--------|-------|--------|---------|
| __init__.py | 1 | 0 | 1 | 100% |
| empty.py | 1 | 1 | 0 | 0% |
| full.py | 25 | 0 | 25 | 100% |
| full.py | 29 | 0 | 29 | 100% |
| partial.py | 29 | 19 | 10 | 34% |
| child_sample/__init__.py | 1 | 1 | 0 | 0% |
| child_sample/child_sample_module.py | 13 | 13 | 0 | 0% |
|------------------------------------------|--------|-------|--------|---------|
| TOTAL | 70 | 34 | 36 | 51.4% |
| TOTAL | 74 | 34 | 40 | 54.1% |
6 changes: 3 additions & 3 deletions tests/functional/fixtures/expected_summary_no_module.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
----------------------------------- Summary ------------------------------------
| Name | Total | Miss | Cover | Cover% |
|------------------------------------------|--------|-------|--------|---------|
| full.py | 24 | 0 | 24 | 100% |
| full.py | 28 | 0 | 28 | 100% |
| partial.py | 28 | 19 | 9 | 32% |
| child_sample/child_sample_module.py | 12 | 12 | 0 | 0% |
|------------------------------------------|--------|-------|--------|---------|
| TOTAL | 64 | 31 | 33 | 51.6% |
---------------- RESULT: FAILED (minimum: 80.0%, actual: 51.6%) ----------------
| TOTAL | 68 | 31 | 37 | 54.4% |
---------------- RESULT: FAILED (minimum: 80.0%, actual: 54.4%) ----------------
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
| child_sample/__init__.py | 1 | 1 | 0 | 0% |
| child_sample/child_sample_module.py | 13 | 13 | 0 | 0% |
|------------------------------------------|--------|-------|--------|---------|
| TOTAL | 70 | 34 | 36 | 51.4% |
| TOTAL | 74 | 34 | 40 | 54.1% |
|------------------------------------------------------------------------------|
| (2 of 6 files omitted due to complete coverage) |
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
| Name | Total | Miss | Cover | Cover% |
|------------------|--------------|-------------|--------------|---------------|
| TOTAL | 25 | 0 | 25 | 100.0% |
| TOTAL | 29 | 0 | 29 | 100.0% |
|------------------------------------------------------------------------------|
| (1 of 1 file omitted due to complete coverage) |
4 changes: 4 additions & 0 deletions tests/functional/fixtures/windows/expected_detailed.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
| Bar.method_bar.InnerBar (L97) | COVERED |
| _SemiprivateClass (L103) | COVERED |
| __PrivateClass (L109) | COVERED |
| InitDocs (L116) | COVERED |
| InitDocs.__init__ (L117) | COVERED |
| ClassDocs (L123) | COVERED |
| ClassDocs.__init__ (L126) | COVERED |
|-----------------------------------------------------------------|-----------|
| partial.py (module) | COVERED |
| Foo (L8) | COVERED |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
| Bar.method_bar.InnerBar (L97) | COVERED |
| _SemiprivateClass (L103) | COVERED |
| __PrivateClass (L109) | COVERED |
| InitDocs (L116) | COVERED |
| InitDocs.__init__ (L117) | COVERED |
| ClassDocs (L123) | COVERED |
| ClassDocs.__init__ (L126) | COVERED |
|-----------------------------------------------------------------|-----------|
| partial.py | |
| Foo (L8) | COVERED |
Expand Down Expand Up @@ -75,9 +79,9 @@
----------------------------------- Summary -----------------------------------
| Name | Total | Miss | Cover | Cover% |
|-----------------------------------------|--------|-------|--------|---------|
| full.py | 24 | 0 | 24 | 100% |
| full.py | 28 | 0 | 28 | 100% |
| partial.py | 28 | 19 | 9 | 32% |
| child_sample\child_sample_module.py | 12 | 12 | 0 | 0% |
|-----------------------------------------|--------|-------|--------|---------|
| TOTAL | 64 | 31 | 33 | 51.6% |
--------------- RESULT: FAILED (minimum: 80.0%, actual: 51.6%) ----------------
| TOTAL | 68 | 31 | 37 | 54.4% |
--------------- RESULT: FAILED (minimum: 80.0%, actual: 54.4%) ----------------
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@
| Bar.method_bar.InnerBar (L97) | COVERED |
| _SemiprivateClass (L103) | COVERED |
| __PrivateClass (L109) | COVERED |
| InitDocs (L116) | COVERED |
| InitDocs.__init__ (L117) | COVERED |
| ClassDocs (L123) | COVERED |
| ClassDocs.__init__ (L126) | COVERED |
|----------------------------------------------------|------------------------|

----------------------------------- Summary -----------------------------------
| Name | Total | Miss | Cover | Cover% |
|-----------------|--------------|-------------|--------------|---------------|
| full.py | 25 | 0 | 25 | 100% |
| full.py | 29 | 0 | 29 | 100% |
|-----------------|--------------|-------------|--------------|---------------|
| TOTAL | 25 | 0 | 25 | 100.0% |
| TOTAL | 29 | 0 | 29 | 100.0% |
--------------- RESULT: PASSED (minimum: 80.0%, actual: 100.0%) ---------------
Original file line number Diff line number Diff line change
@@ -1 +1 @@
RESULT: FAILED (minimum: 80.0%, actual: 51.4%)
RESULT: FAILED (minimum: 80.0%, actual: 54.1%)
4 changes: 2 additions & 2 deletions tests/functional/fixtures/windows/expected_summary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
|-----------------------------------------|--------|-------|--------|---------|
| __init__.py | 1 | 0 | 1 | 100% |
| empty.py | 1 | 1 | 0 | 0% |
| full.py | 25 | 0 | 25 | 100% |
| full.py | 29 | 0 | 29 | 100% |
| partial.py | 29 | 19 | 10 | 34% |
| child_sample\__init__.py | 1 | 1 | 0 | 0% |
| child_sample\child_sample_module.py | 13 | 13 | 0 | 0% |
|-----------------------------------------|--------|-------|--------|---------|
| TOTAL | 70 | 34 | 36 | 51.4% |
| TOTAL | 74 | 34 | 40 | 54.1% |
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
----------------------------------- Summary -----------------------------------
| Name | Total | Miss | Cover | Cover% |
|-----------------------------------------|--------|-------|--------|---------|
| full.py | 24 | 0 | 24 | 100% |
| full.py | 28 | 0 | 28 | 100% |
| partial.py | 28 | 19 | 9 | 32% |
| child_sample\child_sample_module.py | 12 | 12 | 0 | 0% |
|-----------------------------------------|--------|-------|--------|---------|
| TOTAL | 64 | 31 | 33 | 51.6% |
| TOTAL | 68 | 31 | 37 | 54.4% |
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
| child_sample\__init__.py | 1 | 1 | 0 | 0% |
| child_sample\child_sample_module.py | 13 | 13 | 0 | 0% |
|-----------------------------------------|--------|-------|--------|---------|
| TOTAL | 70 | 34 | 36 | 51.4% |
| TOTAL | 74 | 34 | 40 | 54.1% |
Loading

0 comments on commit f77ef6f

Please sign in to comment.