Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quiet config #1

Merged
merged 3 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Change Log

## [0.5.9] - 2024-09-29

- Fixed

- Fixed an edge case where type annotations are very long

- Full diff
- https://github.com/jsh9/pydoclint/compare/0.5.8...0.5.9

## [0.5.8] - 2024-09-23

- Fixed

- Fixed the logic of handling exceptions namespaces (`a.b.c.MyException`)

- Full diff
- https://github.com/jsh9/pydoclint/compare/0.5.7...0.5.8

## [0.5.7] - 2024-09-02

- Added
Expand All @@ -8,8 +26,12 @@
function body match those in the "Raises" section of the docstring

- Changed

- Switched from tab to 4 spaces in baseline

- Full diff
- https://github.com/jsh9/pydoclint/compare/0.5.6...0.5.7

## [0.5.6] - 2024-07-17

- Fixed
Expand Down
44 changes: 44 additions & 0 deletions docs/notes_for_users.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- [4. Notes on writing Sphinx-style docstrings](#4-notes-on-writing-sphinx-style-docstrings)
- [5. Notes for Google-style users](#5-notes-for-google-style-users)
- [6. How to adopt _pydoclint_ more easily in legacy projects](#6-how-to-adopt-pydoclint-more-easily-in-legacy-projects)
- [7. How to integrate _pydoclint_ with different editors or IDEs](#7-how-to-integrate-pydoclint-with-different-editors-or-ides)
- [7.1. Integrate _pydoclint_ with Neovim using null-ls](#71-integrate-pydoclint-with-neovim-using-null-ls)

<!--TOC-->

Expand Down Expand Up @@ -187,3 +189,45 @@ somewhere in your repo.

For more details, please check out
[this section](https://jsh9.github.io/pydoclint/config_options.html#12---baseline).

## 7. How to integrate _pydoclint_ with different editors or IDEs

### 7.1. Integrate _pydoclint_ with Neovim using null-ls

If you use [Neovim](https://neovim.io/), you can integrate _pydoclint_ with
your editor using the [null-ls](https://github.com/nvimtools/none-ls.nvim)
plugin. null-ls allows you to use linters and formatters in Neovim in a simple
and efficient way. First, make sure you have installed null-ls using your
preferred package manager. Next, add the following configuration to your Neovim
config file to register _pydoclint_ as a diagnostic source:

```lua
local null_ls = require("null-ls")

null_ls.setup({
sources = {
null_ls.builtins.diagnostics.pydoclint,
},
})
```

This will enable _pydoclint_ to provide diagnostic messages for your Python
code directly in Neovim. You can further customize the behavior of _pydoclint_
by passing additional options:

```lua
local null_ls = require("null-ls")

null_ls.setup({
sources = {
null_ls.builtins.diagnostics.pydoclint.with({
extra_args = {"--style=google", "--check-return-types=False"},
}),
},
})
```

Adjust the extra*args based on your preferred \_pydoclint* configuration. With
this setup, you can now enjoy the benefits of _pydoclint_'s fast and
comprehensive docstring linting directly within your Neovim editing
environment.
16 changes: 14 additions & 2 deletions pydoclint/utils/generic.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ast
import copy
import re
from typing import List, Match, Optional, Tuple
from typing import List, Match, Optional, Tuple, Union

from pydoclint.utils.astTypes import ClassOrFunctionDef, FuncOrAsyncFuncDef
from pydoclint.utils.method_type import MethodType
Expand Down Expand Up @@ -214,11 +214,15 @@ def appendArgsToCheckToV105(
def specialEqual(str1: str, str2: str) -> bool:
"""
Check string equality but treat any single quotes as the same as
double quotes.
double quotes, and also ignore line breaks in either strings.
"""
if str1 == str2:
return True # using shortcuts to speed up evaluation

if '\n' in str1 or '\n' in str2:
str1 = str1.replace(' ', '').replace('\n', '')
str2 = str2.replace(' ', '').replace('\n', '')

if len(str1) != len(str2):
return False # using shortcuts to speed up evaluation

Expand All @@ -233,3 +237,11 @@ def specialEqual(str1: str, str2: str) -> bool:
return False

return True


def getFullAttributeName(node: Union[ast.Attribute, ast.Name]) -> str:
"""Get the full name of a symbol like a.b.c.foo"""
if isinstance(node, ast.Name):
return node.id

return getFullAttributeName(node.value) + '.' + node.attr
27 changes: 22 additions & 5 deletions pydoclint/utils/return_yield_raise.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pydoclint.utils import walk
from pydoclint.utils.annotation import unparseAnnotation
from pydoclint.utils.astTypes import BlockType, FuncOrAsyncFuncDef
from pydoclint.utils.generic import stringStartsWith
from pydoclint.utils.generic import getFullAttributeName, stringStartsWith

ReturnType = Type[ast.Return]
ExprType = Type[ast.Expr]
Expand Down Expand Up @@ -132,7 +132,17 @@ def _getRaisedExceptions(
):
for subnode, _ in walk.walk_dfs(child):
if isinstance(subnode, ast.Name):
yield subnode.id
if isinstance(child.exc, ast.Attribute):
# case: looks like m.n.exception
yield getFullAttributeName(child.exc)
elif isinstance(child.exc, ast.Call) and isinstance(
child.exc.func, ast.Attribute
):
# case: looks like m.n.exception()
yield getFullAttributeName(child.exc.func)
else:
yield subnode.id

break
else:
# if "raise" statement was alone, it must be inside an "except"
Expand All @@ -148,10 +158,17 @@ def _extractExceptionsFromExcept(
if isinstance(node.type, ast.Name):
yield node.type.id

if isinstance(node.type, ast.Attribute):
# case: looks like m.n.exception
yield getFullAttributeName(node.type)

if isinstance(node.type, ast.Tuple):
for child, _ in walk.walk(node.type):
if isinstance(child, ast.Name):
yield child.id
for elt in node.type.elts:
if isinstance(elt, ast.Attribute):
# case: looks like m.n.exception
yield getFullAttributeName(elt)
elif isinstance(elt, ast.Name):
yield elt.id


def _hasExpectedStatements(
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = pydoclint
version = 0.5.7
version = 0.5.9
description = A Python docstring linter that checks arguments, returns, yields, and raises sections
long_description = file: README.md
long_description_content_type = text/markdown
Expand Down
32 changes: 32 additions & 0 deletions tests/data/edge_cases/15_very_long_annotations/google.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This edge case was reported in https://github.com/jsh9/pydoclint/issues/164

# fmt: off
import numpy as np


def func(
arg1: tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
],
) -> tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray]:
"""
The docstring parser for the Google style does not support line breaking
in type hints. Therefore, in order to pass pydoclint's checks, we can only
put long type hints in one line.

Args:
arg1 (tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]): A parameter

Returns:
tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]: The return value
"""
return (
np.array([]), np.array([]), np.array([]), np.array([]), np.array([]),
np.array([]), np.array([]), np.array([]), np.array([]),
)

# fmt: on
37 changes: 37 additions & 0 deletions tests/data/edge_cases/15_very_long_annotations/numpy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This edge case was reported in https://github.com/jsh9/pydoclint/issues/164

# fmt: off

import numpy as np


def func(
arg1: tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
],
) -> tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray]:
"""
The docstring parser for the numpy style does not support line breaking
in type hints. Therefore, in order to pass pydoclint's checks, we can only
put long type hints in one line.

Parameters
----------
arg1 : tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]
A parameter

Returns
-------
tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]
The return value
"""
return (
np.array([]), np.array([]), np.array([]), np.array([]), np.array([]),
np.array([]), np.array([]), np.array([]), np.array([]),
)

# fmt: on
36 changes: 36 additions & 0 deletions tests/data/edge_cases/15_very_long_annotations/sphinx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# This edge case was reported in https://github.com/jsh9/pydoclint/issues/164

# fmt: off

import numpy as np


def func(
arg1: tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
],
) -> tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray]:
"""Something

:param arg1: A parameter
:type arg1: tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
]

:returns: Numpy arrays
:rtype: tuple[
np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray,
np.ndarray, np.ndarray, np.ndarray]
"""
return (
np.array([]), np.array([]), np.array([]), np.array([]), np.array([]),
np.array([]), np.array([]), np.array([]), np.array([]),
)

# fmt: on
23 changes: 23 additions & 0 deletions tests/data/google/raises/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,26 @@ def func13(self) -> None:
ValueError: typo!
"""
raise ValueError

def func14(self) -> None:
"""
Should fail, expects `exceptions.CustomError`.

Raises:
CustomError: every time.
"""
exceptions = object()
exceptions.CustomError = CustomError
raise exceptions.CustomError()

def func15(self) -> None:
"""
Should fail, expects `exceptions.m.CustomError`.

Raises:
CustomError: every time.
"""
exceptions = object()
exceptions.m = object()
exceptions.m.CustomError = CustomError
raise exceptions.m.CustomError
27 changes: 27 additions & 0 deletions tests/data/numpy/raises/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,30 @@ def func13(self) -> None:
typo!
"""
raise ValueError

def func14(self) -> None:
"""
Should fail, expects `exceptions.CustomError`.

Raises
------
CustomError
every time.
"""
exceptions = object()
exceptions.CustomError = CustomError
raise exceptions.CustomError()

def func15(self) -> None:
"""
Should fail, expects `exceptions.m.CustomError`.

Raises
------
CustomError
every time.
"""
exceptions = object()
exceptions.m = object()
exceptions.m.CustomError = CustomError
raise exceptions.m.CustomError
21 changes: 21 additions & 0 deletions tests/data/sphinx/raises/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,24 @@ def func13(self) -> None:
:raises ValueError: typo!
"""
raise ValueError

def func14(self) -> None:
"""
Should fail, expects `exceptions.CustomError`.

:raises CustomError: every time.
"""
exceptions = object()
exceptions.CustomError = CustomError
raise exceptions.CustomError()

def func15(self) -> None:
"""
Should fail, expects `exceptions.m.CustomError`.

:raises CustomError: every time.
"""
exceptions = object()
exceptions.m = object()
exceptions.m.CustomError = CustomError
raise exceptions.m.CustomError
Loading