Skip to content

Commit

Permalink
add: Add -k/--ignore-kwargs argument (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
jshwi committed Dec 19, 2022
1 parent d4ca3bc commit 6b4ba2b
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
[Unreleased](https://github.com/jshwi/docsig/compare/v0.32.0...HEAD)
------------------------------------------------------------------------
### Added
- Add `-k/--ignore-kwargs` argument
- Add `-a/--ignore-args` argument

[0.32.0](https://github.com/jshwi/docsig/releases/tag/v0.32.0) - 2022-12-11
Expand Down
5 changes: 3 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ Commandline

.. code-block:: console
usage: docsig [-h] [-v] [-c] [-D] [-o] [-p] [-P] [-i] [-a] [-n] [-S] [-s STR] [-d LIST]
[-t LIST]
usage: docsig [-h] [-v] [-c] [-D] [-o] [-p] [-P] [-i] [-a] [-k] [-n] [-S] [-s STR]
[-d LIST] [-t LIST]
[path [path ...]]
Check signature params for proper documentation
Expand All @@ -61,6 +61,7 @@ Commandline
-P, --check-property-returns check property return values
-i, --ignore-no-params ignore docstrings where parameters are not documented
-a, --ignore-args ignore args prefixed with an asterisk
-k, --ignore-kwargs ignore kwargs prefixed with two asterisks
-n, --no-ansi disable ansi output
-S, --summary print a summarised report
-s STR, --string STR string to parse instead of files
Expand Down
6 changes: 6 additions & 0 deletions docsig/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ def _add_arguments(self) -> None:
action="store_true",
help="ignore args prefixed with an asterisk",
)
self.add_argument(
"-k",
"--ignore-kwargs",
action="store_true",
help="ignore kwargs prefixed with two asterisks",
)
self.add_argument(
"-n", "--no-ansi", action="store_true", help="disable ansi output"
)
Expand Down
9 changes: 8 additions & 1 deletion docsig/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def docsig( # pylint: disable=too-many-locals
check_property_returns: bool = False,
ignore_no_params: bool = False,
ignore_args: bool = False,
ignore_kwargs: bool = False,
no_ansi: bool = False,
summary: bool = False,
targets: list[str] | None = None,
Expand All @@ -80,13 +81,19 @@ def docsig( # pylint: disable=too-many-locals
:param ignore_no_params: Ignore docstrings where parameters are not
documented
:param ignore_args: Ignore args prefixed with an asterisk.
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
:param no_ansi: Disable ANSI output.
:param summary: Print a summarised report.
:param targets: List of errors to target.
:param disable: List of errors to disable.
:return: Exit status for whether test failed or not.
"""
modules = _Modules(*path, string=string, ignore_args=ignore_args)
modules = _Modules(
*path,
string=string,
ignore_args=ignore_args,
ignore_kwargs=ignore_kwargs,
)
display = _Display(no_ansi)
for module in modules:
for top_level in module:
Expand Down
36 changes: 27 additions & 9 deletions docsig/_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,23 @@ def __init__(self, string: str) -> None:


class _Params(_MutableSequence[Param]):
def __init__(self, ignore_args: bool = False) -> None:
def __init__(
self, ignore_args: bool = False, ignore_kwargs: bool = False
) -> None:
super().__init__()
self._ignore_args = ignore_args
self._ignore_kwargs = ignore_kwargs

# pylint: disable=too-many-boolean-expressions
def insert(self, index: int, value: Param) -> None:
if not value.isprotected and (
value.kind == PARAM
or (value.kind == ARG and not self._ignore_args)
or (value.kind == KEY and not any(i.kind == KEY for i in self))
or (
value.kind == KEY
and not self._ignore_kwargs
and not any(i.kind == KEY for i in self)
)
):
super().insert(index, value)

Expand All @@ -143,8 +150,10 @@ def duplicated(self) -> bool:


class _DocSig:
def __init__(self, ignore_args: bool = False) -> None:
self._args = _Params(ignore_args)
def __init__(
self, ignore_args: bool = False, ignore_kwargs: bool = False
) -> None:
self._args = _Params(ignore_args, ignore_kwargs)
self._returns = False

@property
Expand All @@ -166,8 +175,9 @@ def __init__( # pylint: disable=too-many-arguments
ismethod: bool = False,
isstaticmethod: bool = False,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__(ignore_args)
super().__init__(ignore_args, ignore_kwargs)
if ismethod and not isstaticmethod and arguments.args:
arguments.args.pop(0)

Expand Down Expand Up @@ -218,9 +228,12 @@ def rettype(self) -> str | None:

class _Docstring(_DocSig):
def __init__(
self, node: _ast.Const | None = None, ignore_args: bool = False
self,
node: _ast.Const | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__(ignore_args)
super().__init__(ignore_args, ignore_kwargs)
self._string = None
if node is not None:
self._string = _RawDocstring(node.value)
Expand Down Expand Up @@ -249,10 +262,14 @@ class Function:
:param node: Function's abstract syntax tree.
:param ignore_args: Ignore args prefixed with an asterisk.
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
"""

def __init__(
self, node: _ast.FunctionDef, ignore_args: bool = False
self,
node: _ast.FunctionDef,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
self._node = node
self._parent = node.parent.frame()
Expand All @@ -262,10 +279,11 @@ def __init__(
self.ismethod,
self.isstaticmethod,
ignore_args,
ignore_kwargs,
)
self._docstring = _Docstring(
node.doc_node if not self.isinit else self._parent.doc_node,
ignore_args,
ignore_kwargs,
)

def __len__(self) -> int:
Expand Down
1 change: 1 addition & 0 deletions docsig/_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def main() -> int:
check_property_returns=parser.args.check_property_returns,
ignore_no_params=parser.args.ignore_no_params,
ignore_args=parser.args.ignore_args,
ignore_kwargs=parser.args.ignore_kwargs,
no_ansi=parser.args.no_ansi,
summary=parser.args.summary,
targets=parser.args.target,
Expand Down
27 changes: 22 additions & 5 deletions docsig/_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,22 @@ class Parent(_MutableSequence[_Function]):
:param node: Parent's abstract syntax tree.
:param path: Path to base path representation on.
:param ignore_args: Ignore args prefixed with an asterisk.
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
"""

def __init__(
self,
node: _ast.Module | _ast.ClassDef,
path: _Path | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__()
self._name = node.name
self._path = f"{path}:" if path is not None else ""
for subnode in node.body:
if isinstance(subnode, _ast.FunctionDef):
self.append(_Function(subnode, ignore_args))
self.append(_Function(subnode, ignore_args, ignore_kwargs))

@property
def path(self) -> str:
Expand All @@ -57,12 +59,13 @@ def __init__(
node: _ast.Module,
path: _Path | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__()
self.append(Parent(node, path, ignore_args))
self.append(Parent(node, path, ignore_args, ignore_kwargs))
for subnode in node.body:
if isinstance(subnode, _ast.ClassDef):
self.append(Parent(subnode, path, ignore_args))
self.append(Parent(subnode, path, ignore_args, ignore_kwargs))


class Modules(_MutableSequence[_Module]):
Expand All @@ -76,26 +79,40 @@ class Modules(_MutableSequence[_Module]):
:param paths: Path(s) to pase ``Module``(s) from.
:param string: String to parse if provided.
:param ignore_args: Ignore args prefixed with an asterisk.
:param ignore_kwargs: Ignore kwargs prefixed with two asterisks.
"""

def __init__(
self,
*paths: _Path,
string: str | None = None,
ignore_args: bool = False,
ignore_kwargs: bool = False,
) -> None:
super().__init__()
self._ignore_args = ignore_args
self._ignore_kwargs = ignore_kwargs
if string is not None:
self.append(_Module(_ast.parse(string), ignore_args=ignore_args))
self.append(
_Module(
_ast.parse(string),
ignore_args=ignore_args,
ignore_kwargs=ignore_kwargs,
)
)
else:
for path in paths:
self._populate(path)

def _populate(self, root: _Path) -> None:
if root.is_file() and root.name.endswith(".py"):
self.append(
_Module(_ast.parse(root.read_text()), root, self._ignore_args)
_Module(
_ast.parse(root.read_text()),
root,
self._ignore_args,
self._ignore_kwargs,
)
)

if root.is_dir():
Expand Down
40 changes: 40 additions & 0 deletions tests/_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -845,3 +845,43 @@ def test_ignore_args(
or name.startswith(PASS)
and "w-args" in name
)


@pytest.mark.parametrize(
[NAME, TEMPLATE, "_"],
templates.registered.filtergroup(MULTI),
ids=templates.registered.filtergroup(MULTI).getids(),
)
def test_ignore_kwargs(
init_file: InitFileFixtureType,
main: MockMainType,
name: str,
template: str,
_: str,
) -> None:
"""Test docstrings without kwargs don't fail wih ``-k``.
Passing tests will fail and failing tests will pass, as tests which
generally pass will have kwargs documented, which shouldn't be with
this argument.
:param init_file: Initialize a test file.
:param main: Mock ``main`` function.
:param name: Name of test.
:param template: Contents to write to file.
"""
file = init_file(template)
assert main(
long.check_class,
long.check_protected,
long.check_overridden,
long.check_dunders,
long.check_property_returns,
long.ignore_kwargs,
file.parent,
) == int(
name.startswith(FAIL)
and "w-kwargs" not in name
or name.startswith(PASS)
and "w-kwargs" in name
)

0 comments on commit 6b4ba2b

Please sign in to comment.