Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 0 additions & 9 deletions doc/user_guide/configuration/all-options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,6 @@ Standard Checkers
**Default:** ``()``


--suggestion-mode
"""""""""""""""""
*When enabled, pylint would attempt to guess common misconfiguration and emit user-friendly hints instead of false-positive error messages.*

**Default:** ``True``


--unsafe-load-any-extension
"""""""""""""""""""""""""""
*Allow loading of arbitrary C extensions. Extensions are imported into the active Python interpreter and may run arbitrary code.*
Expand Down Expand Up @@ -290,8 +283,6 @@ Standard Checkers

source-roots = []

suggestion-mode = true

unsafe-load-any-extension = false


Expand Down
4 changes: 4 additions & 0 deletions doc/whatsnew/fragments/9962.breaking
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The ``suggestion-mode`` option was removed, as pylint now always emits user-friendly hints instead
of false-positive error messages. You should remove it from your conf if it's defined.

Refs #9962
4 changes: 0 additions & 4 deletions examples/pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,6 @@ recursive=no
# source root.
source-roots=

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes

# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
Expand Down
4 changes: 0 additions & 4 deletions examples/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ py-version = "3.12"
# source root.
# source-roots =

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode = true

# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
# unsafe-load-any-extension =
Expand Down
37 changes: 37 additions & 0 deletions pylint/checkers/clear_lru_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from pylint.checkers.typecheck import _similar_names
from pylint.checkers.utils import (
class_is_abstract,
in_for_else_branch,
infer_all,
is_overload_stub,
overridden_method,
safe_infer,
unimplemented_abstract_methods,
)

if TYPE_CHECKING:
from functools import _lru_cache_wrapper


def clear_lru_caches() -> None:
"""Clear caches holding references to AST nodes."""
caches_holding_node_references: list[_lru_cache_wrapper[Any]] = [
class_is_abstract,
in_for_else_branch,
infer_all,
is_overload_stub,
overridden_method,
unimplemented_abstract_methods,
safe_infer,
_similar_names,
]
for lru in caches_holding_node_references:
lru.cache_clear()
59 changes: 18 additions & 41 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import shlex
import sys
from collections.abc import Callable, Iterable
from functools import cached_property, singledispatch
from functools import cached_property, lru_cache, singledispatch
from re import Pattern
from typing import TYPE_CHECKING, Any, Literal, Union

Expand Down Expand Up @@ -172,6 +172,7 @@ def _string_distance(seq1: str, seq2: str, seq1_length: int, seq2_length: int) -
return row[seq2_length - 1]


@lru_cache(maxsize=256)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this to clear_lru_caches()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This created a circular import between typecheck and utils so I created a new file.

def _similar_names(
owner: SuccessfulInferenceResult,
attrname: str | None,
Expand Down Expand Up @@ -214,26 +215,6 @@ def _similar_names(
return sorted(picked)


def _missing_member_hint(
owner: SuccessfulInferenceResult,
attrname: str | None,
distance_threshold: int,
max_choices: int,
) -> str:
names = _similar_names(owner, attrname, distance_threshold, max_choices)
if not names:
# No similar name.
return ""

names = [repr(name) for name in names]
if len(names) == 1:
names_hint = ", ".join(names)
else:
names_hint = f"one of {', '.join(names[:-1])} or {names[-1]}"

return f"; maybe {names_hint}?"


MSGS: dict[str, MessageDefinitionTuple] = {
"E1101": (
"%s %r has no %r member%s",
Expand Down Expand Up @@ -997,10 +978,6 @@ def open(self) -> None:
self._py310_plus = py_version >= (3, 10)
self._mixin_class_rgx = self.linter.config.mixin_class_rgx

@cached_property
def _suggestion_mode(self) -> bool:
return self.linter.config.suggestion_mode # type: ignore[no-any-return]

@cached_property
def _compiled_generated_members(self) -> tuple[Pattern[str], ...]:
# do this lazily since config not fully initialized in __init__
Expand Down Expand Up @@ -1211,24 +1188,24 @@ def _get_nomember_msgid_hint(
node: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr,
owner: SuccessfulInferenceResult,
) -> tuple[Literal["c-extension-no-member", "no-member"], str]:
suggestions_are_possible = self._suggestion_mode and isinstance(
owner, nodes.Module
if _is_c_extension(owner):
return "c-extension-no-member", ""
if not self.linter.config.missing_member_hint:
return "no-member", ""
names = _similar_names(
owner,
node.attrname,
self.linter.config.missing_member_hint_distance,
self.linter.config.missing_member_max_choices,
)
if suggestions_are_possible and _is_c_extension(owner):
msg = "c-extension-no-member"
hint = ""
if not names:
return "no-member", ""
names = [repr(name) for name in names]
if len(names) == 1:
names_hint = names[0]
else:
msg = "no-member"
if self.linter.config.missing_member_hint:
hint = _missing_member_hint(
owner,
node.attrname,
self.linter.config.missing_member_hint_distance,
self.linter.config.missing_member_max_choices,
)
else:
hint = ""
return msg, hint # type: ignore[return-value]
names_hint = f"one of {', '.join(names[:-1])} or {names[-1]}"
return "no-member", f"; maybe {names_hint}?"

@only_required_for_messages(
"assignment-from-no-return",
Expand Down
18 changes: 1 addition & 17 deletions pylint/checkers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from collections.abc import Callable, Iterable, Iterator
from functools import lru_cache, partial
from re import Match
from typing import TYPE_CHECKING, Any, TypeVar
from typing import TYPE_CHECKING, TypeVar

import astroid.objects
from astroid import TooManyLevelsError, nodes, util
Expand All @@ -28,7 +28,6 @@
from pylint.constants import TYPING_NEVER, TYPING_NORETURN

if TYPE_CHECKING:
from functools import _lru_cache_wrapper

from pylint.checkers import BaseChecker

Expand Down Expand Up @@ -2327,21 +2326,6 @@ def overridden_method(
return None # pragma: no cover


def clear_lru_caches() -> None:
"""Clear caches holding references to AST nodes."""
caches_holding_node_references: list[_lru_cache_wrapper[Any]] = [
class_is_abstract,
in_for_else_branch,
infer_all,
is_overload_stub,
overridden_method,
unimplemented_abstract_methods,
safe_infer,
]
for lru in caches_holding_node_references:
lru.cache_clear()


def is_enum_member(node: nodes.AssignName) -> bool:
"""Return `True` if `node` is an Enum member (is an item of the
`__members__` container).
Expand Down
13 changes: 0 additions & 13 deletions pylint/lint/base_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,19 +306,6 @@ def _make_linter_options(linter: PyLinter) -> Options:
),
},
),
(
"suggestion-mode",
{
"type": "yn",
"metavar": "<y or n>",
"default": True,
"help": (
"When enabled, pylint would attempt to guess common "
"misconfiguration and emit user-friendly hints instead "
"of false-positive error messages."
),
},
),
(
"exit-zero",
{
Expand Down
2 changes: 1 addition & 1 deletion pylint/lint/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from typing import ClassVar

from pylint import config
from pylint.checkers.utils import clear_lru_caches
from pylint.checkers.clear_lru_cache import clear_lru_caches
from pylint.config._pylint_config import (
_handle_pylint_config_commands,
_register_generate_config_options,
Expand Down
1 change: 0 additions & 1 deletion pylint/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@

# These are types used to overload get_global_option() and refer to the options type
GLOBAL_OPTION_BOOL = Literal[
"suggestion-mode",
"analyse-fallback-blocks",
"allow-global-unused-variables",
"prefer-stubs",
Expand Down
4 changes: 0 additions & 4 deletions pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ load-plugins=
# number of processors available to use.
jobs=1

# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes

# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
Expand Down
25 changes: 1 addition & 24 deletions tests/checkers/unittest_typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from pylint.checkers import typecheck
from pylint.interfaces import INFERENCE, UNDEFINED
from pylint.testutils import CheckerTestCase, MessageTest, set_config
from pylint.testutils import CheckerTestCase, MessageTest

try:
from coverage import tracer as _
Expand All @@ -27,29 +27,6 @@ class TestTypeChecker(CheckerTestCase):

CHECKER_CLASS = typecheck.TypeChecker

@set_config(suggestion_mode=False)
@needs_c_extension
def test_nomember_on_c_extension_error_msg(self) -> None:
node = astroid.extract_node(
"""
from coverage import tracer
tracer.CTracer #@
"""
)
message = MessageTest(
"no-member",
node=node,
args=("Module", "coverage.tracer", "CTracer", ""),
confidence=INFERENCE,
line=3,
col_offset=0,
end_line=3,
end_col_offset=14,
)
with self.assertAddsMessages(message):
self.checker.visit_attribute(node)

@set_config(suggestion_mode=True)
@needs_c_extension
def test_nomember_on_c_extension_info_msg(self) -> None:
node = astroid.extract_node(
Expand Down
Loading