Skip to content

Commit

Permalink
New checker - Detect use of unnecessary ellipsis
Browse files Browse the repository at this point in the history
Closes #5460
  • Loading branch information
mbyrnepr2 committed Dec 7, 2021
1 parent 3ed7a8e commit a285bc3
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 3 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Release date: TBA

Closes #5323

* Add checker ``unnecessary-ellipsis``

Closes #5460

* Fixed detection of ``arguments-differ`` when superclass static
methods lacked a ``@staticmethod`` decorator.

Expand Down
3 changes: 3 additions & 0 deletions doc/whatsnew/2.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Summary -- Release highlights

New checkers
============
* ``unnecessary-ellipsis``: Emmitted when the ellipsis constant is used unnecessarily.

Closes #5460

Removed checkers
================
Expand Down
20 changes: 20 additions & 0 deletions pylint/checkers/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,11 @@ class StringConstantChecker(BaseTokenChecker):
"in Python 2 to indicate a string was Unicode, but since Python 3.0 strings "
"are Unicode by default.",
),
"W1407": (
"Unnecessary ellipsis constant",
"unnecessary-ellipsis",
"Used when the ellipsis constant is encountered and can be avoided.",
),
}
options = (
(
Expand Down Expand Up @@ -914,6 +919,7 @@ def visit_const(self, node: nodes.Const) -> None:
node.parent, nodes.JoinedStr
):
self._detect_u_string_prefix(node)
self._detect_ellipsis(node)

def _detect_u_string_prefix(self, node: nodes.Const):
"""Check whether strings include a 'u' prefix like u'String'"""
Expand All @@ -924,6 +930,20 @@ def _detect_u_string_prefix(self, node: nodes.Const):
col_offset=node.col_offset,
)

def _detect_ellipsis(self, node: nodes.Const) -> None:
"""Check if the ellipsis constant is used unnecessarily"""
if node.value is not Ellipsis or isinstance(
node.parent, (nodes.Assign, nodes.AnnAssign)
):
return
if len(node.parent.parent.child_sequence(node.parent)) > 1 or (
isinstance(node.parent.parent, (nodes.ClassDef, nodes.FunctionDef))
and (node.parent.parent.doc is not None)
):
self.add_message(
"unnecessary-ellipsis", line=node.lineno, col_offset=node.col_offset
)


def register(linter):
"""required method to auto register this checker"""
Expand Down
1 change: 0 additions & 1 deletion tests/functional/c/class_members.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

class Class:
attr: int
...


# `bar` definitely does not exist here, but in a complex scenario,
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/s/statement_without_effect.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Test for statements without effects."""
# pylint: disable=too-few-public-methods, useless-object-inheritance, unnecessary-comprehension, use-list-literal
# pylint: disable=too-few-public-methods, useless-object-inheritance, unnecessary-comprehension, unnecessary-ellipsis, use-list-literal

# +1:[pointless-string-statement]
"""inline doc string should use a separated message"""
Expand Down
1 change: 0 additions & 1 deletion tests/functional/t/too/too_few_public_methods_excluded.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ class MyJsonEncoder(JSONEncoder):
class InheritedInModule(Control):
"""This class inherits from a class that doesn't have enough mehods,
and its parent is excluded via config, so it doesn't raise."""
...
54 changes: 54 additions & 0 deletions tests/functional/u/unnecessary/unnecessary_ellipsis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Emit a warning when the ellipsis constant is used and can be avoided"""

# pylint: disable=missing-docstring, too-few-public-methods

try:
A = 2
except ValueError:
A = 24
... # [unnecessary-ellipsis]

B = ...
C = [..., 1, 2, 3]

def docstring_only():
'''In Python, stubbed functions often have a body that contains just a
single `...` constant, indicating that the function doesn't do
anything. However, a stubbed function can also have just a
docstring, and function with a docstring and no body also does
nothing.
'''


# This function has no docstring, so it needs a `...` constant.
def ellipsis_only():
...


def docstring_and_ellipsis():
'''This function doesn't do anything, but it has a docstring, so its
`...` constant is useless clutter.
NEW CHECK: unnecessary-ellipsis
This would check for stubs with both docstrings and `...`
constants, suggesting the removal of the useless `...`
constants
'''
... # [unnecessary-ellipsis]


class DocstringOnly:
'''The same goes for class stubs: docstring, or `...`, but not both.
'''


# No problem
class EllipsisOnly:
...


class DocstringAndEllipsis:
'''Whoops! Mark this one as bad too.
'''
... # [unnecessary-ellipsis]
3 changes: 3 additions & 0 deletions tests/functional/u/unnecessary/unnecessary_ellipsis.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
unnecessary-ellipsis:9:4:None:None::Unnecessary ellipsis constant:UNDEFINED
unnecessary-ellipsis:38:4:None:None::Unnecessary ellipsis constant:UNDEFINED
unnecessary-ellipsis:54:4:None:None::Unnecessary ellipsis constant:UNDEFINED

0 comments on commit a285bc3

Please sign in to comment.