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

Release branch 2.15.1 #7393

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
2 changes: 1 addition & 1 deletion .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:

env:
# Also change CACHE_VERSION in the other workflows
CACHE_VERSION: 22
CACHE_VERSION: 25
DEFAULT_PYTHON: "3.10"

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
pull_request: ~

env:
CACHE_VERSION: 22
CACHE_VERSION: 25
DEFAULT_PYTHON: "3.10"
PRE_COMMIT_CACHE: ~/.cache/pre-commit

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
- ".github/workflows/primer-test.yaml"

env:
CACHE_VERSION: 22
CACHE_VERSION: 25

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer_comment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ on:

env:
# This needs to be the SAME as in the Main and PR job
CACHE_VERSION: 22
CACHE_VERSION: 25

permissions:
contents: read
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer_run_main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ concurrency:

env:
# This needs to be the SAME as in the PR and comment job
CACHE_VERSION: 22
CACHE_VERSION: 25

jobs:
run-primer:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer_run_pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ concurrency:

env:
# This needs to be the SAME as in the Main and comment job
CACHE_VERSION: 22
CACHE_VERSION: 25

jobs:
run-primer:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
- doc/data/messages/**

env:
CACHE_VERSION: 22
CACHE_VERSION: 25

jobs:
tests-linux:
Expand Down
3 changes: 3 additions & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ contributors:
- Ry4an Brase <ry4an-hg@ry4an.org>
- Ruro <ruro.ruro@ya.ru>
- Roman Ivanov <me@roivanov.com>
- Rogdham <contact@rogdham.net>
- Robert Schweizer <robert_schweizer@gmx.de>
- Reverb Chu <reverbc@users.noreply.github.com>
- Renat Galimov <renat2017@gmail.com>
Expand Down Expand Up @@ -422,6 +423,7 @@ contributors:
- Louis Sautier <sautier.louis@gmail.com>
- Lorena Buciu <46202743+lorena-b@users.noreply.github.com>
- Logan Miller <14319179+komodo472@users.noreply.github.com>
- Levi Gruspe <mail.levig@gmail.com>
- Kári Tristan Helgason <kthelgason@gmail.com>
- Kurian Benoy <70306694+kurianbenoy-aot@users.noreply.github.com>
- Krzysztof Czapla <k.czapla68@gmail.com>
Expand Down Expand Up @@ -500,6 +502,7 @@ contributors:
- Craig Citro <craigcitro@gmail.com>
- Clément Pit-Claudel <cpitclaudel@users.noreply.github.com>
- Christopher Zurcher <zurcher@users.noreply.github.com>
- Christoph Blessing <33834216+cblessing24@users.noreply.github.com>
- Carl Crowder <bitbucket@carlcrowder.com>: don't evaluate the value of arguments for 'dangerous-default-value'
- Carey Metcalfe <carey@cmetcalfe.ca>: demoted `try-except-raise` from error to warning
- Cameron Olechowski <camsterole@users.noreply.github.com>
Expand Down
48 changes: 48 additions & 0 deletions doc/whatsnew/2/2.15/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,50 @@ Marc Byrne became a maintainer, welcome to the team !

.. towncrier release notes start


What's new in Pylint 2.15.1?
----------------------------
Release date: 2022-09-06

- Fix ``used-before-assignment`` for functions/classes defined in type checking guard.

Closes #7368 (`#7368 <https://github.com/PyCQA/pylint/issues/7368>`_)
- Update ``modified_iterating`` checker to fix a crash with ``for`` loops on empty list.

Closes #7380 (`#7380 <https://github.com/PyCQA/pylint/issues/7380>`_)
- The ``docparams`` extension now considers typing in Numpy style docstrings
as "documentation" for the ``missing-param-doc`` message.

Refs #7398 (`#7398 <https://github.com/PyCQA/pylint/issues/7398>`_)
- Fix false positive for ``unused-variable`` and ``unused-import`` when a name is only used in a string literal type annotation.

Closes #3299 (`#3299 <https://github.com/PyCQA/pylint/issues/3299>`_)
- Fix false positive for ``too-many-function-args`` when a function call is assigned to a class attribute inside the class where the function is defined.

Closes #6592 (`#6592 <https://github.com/PyCQA/pylint/issues/6592>`_)
- Fix ``used-before-assignment`` for functions/classes defined in type checking guard.

Closes #7368 (`#7368 <https://github.com/PyCQA/pylint/issues/7368>`_)
- Fix ignored files being linted when passed on stdin.

Closes #4354 (`#4354 <https://github.com/PyCQA/pylint/issues/4354>`_)
- ``missing-return-doc``, ``missing-raises-doc`` and ``missing-yields-doc`` now respect
Copy link
Collaborator

Choose a reason for hiding this comment

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

Doesn't towncrier know about white spaces? 😅

Copy link
Member Author

Choose a reason for hiding this comment

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

I manually removed the duplicated titles, which is why there might be some problems.

Copy link
Member Author

Choose a reason for hiding this comment

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

Let's fix in #7426

the ``no-docstring-rgx`` option.

Closes #4743 (`#4743 <https://github.com/PyCQA/pylint/issues/4743>`_)
- Don't crash on ``OSError`` in config file discovery.

Closes #7169 (`#7169 <https://github.com/PyCQA/pylint/issues/7169>`_)
- ``disable-next`` is now correctly scoped to only the succeeding line.

Closes #7401 (`#7401 <https://github.com/PyCQA/pylint/issues/7401>`_)
- Update ``modified_iterating`` checker to fix a crash with ``for`` loops on empty list.

Closes #7380 (`#7380 <https://github.com/PyCQA/pylint/issues/7380>`_)

What's new in Pylint 2.15.0?
----------------------------

New Checks
----------

Expand Down Expand Up @@ -72,6 +116,10 @@ False Positives Fixed
- Fix `undefined-loop-variable` with `break` and `continue` statements in `else` blocks.

Refs #7311 (`#7311 <https://github.com/PyCQA/pylint/issues/7311>`_)
- Improve default TypeVar name regex. Disallow names prefixed with ``T``.
E.g. use ``AnyStrT`` instead of ``TAnyStr``.

Refs #7322 (`#7322 <https://github.com/PyCQA/pylint/issues/7322>`_`)


False Negatives Fixed
Expand Down
4 changes: 0 additions & 4 deletions doc/whatsnew/fragments/7322.false-positive

This file was deleted.

8 changes: 6 additions & 2 deletions pylint/checkers/modified_iterating_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def _modified_iterating_check(
msg_id = "modified-iterating-dict"
elif isinstance(inferred, nodes.Set):
msg_id = "modified-iterating-set"
elif not isinstance(iter_obj, nodes.Name):
elif not isinstance(iter_obj, (nodes.Name, nodes.Attribute)):
pass
elif self._modified_iterating_list_cond(node, iter_obj):
msg_id = "modified-iterating-list"
Expand All @@ -90,10 +90,14 @@ def _modified_iterating_check(
elif self._modified_iterating_set_cond(node, iter_obj):
msg_id = "modified-iterating-set"
if msg_id:
if isinstance(iter_obj, nodes.Attribute):
obj_name = iter_obj.attrname
else:
obj_name = iter_obj.name
self.add_message(
msg_id,
node=node,
args=(iter_obj.name,),
args=(obj_name,),
confidence=interfaces.INFERENCE,
)

Expand Down
13 changes: 13 additions & 0 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,19 @@ def visit_call(self, node: nodes.Call) -> None:
keyword_args += list(already_filled_keywords)
num_positional_args += implicit_args + already_filled_positionals

# Decrement `num_positional_args` by 1 when a function call is assigned to a class attribute
# inside the class where the function is defined.
# This avoids emitting `too-many-function-args` since `num_positional_args`
# includes an implicit `self` argument which is not present in `called.args`.
if (
isinstance(node.frame(), nodes.ClassDef)
and isinstance(node.parent, (nodes.Assign, nodes.AnnAssign))
and isinstance(called, nodes.FunctionDef)
and called in node.frame().body
and num_positional_args > 0
):
num_positional_args -= 1

# Analyze the list of formal parameters.
args = list(itertools.chain(called.args.posonlyargs or (), called.args.args))
num_mandatory_parameters = len(args) - len(called.args.defaults)
Expand Down
22 changes: 22 additions & 0 deletions pylint/checkers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,28 @@ def in_type_checking_block(node: nodes.NodeNG) -> bool:
return False


def is_typing_literal(node: nodes.NodeNG) -> bool:
"""Check if a node refers to typing.Literal."""
if isinstance(node, nodes.Name):
try:
import_from = node.lookup(node.name)[1][0]
except IndexError:
return False
if isinstance(import_from, nodes.ImportFrom):
return (
import_from.modname == "typing"
and import_from.real_name(node.name) == "Literal"
)
elif isinstance(node, nodes.Attribute):
inferred_module = safe_infer(node.expr)
return (
isinstance(inferred_module, nodes.Module)
and inferred_module.name == "typing"
and node.attrname == "Literal"
)
return False


@lru_cache()
def in_for_else_branch(parent: nodes.NodeNG, stmt: nodes.Statement) -> bool:
"""Returns True if stmt is inside the else branch for a parent For stmt."""
Expand Down
54 changes: 48 additions & 6 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from typing import TYPE_CHECKING, Any, NamedTuple

import astroid
from astroid import nodes
from astroid import extract_node, nodes
from astroid.typing import InferenceResult

from pylint.checkers import BaseChecker, utils
Expand Down Expand Up @@ -1841,7 +1841,6 @@ def _is_variable_violation(
base_scope_type,
is_recursive_klass,
) -> tuple[bool, bool, bool]:
# pylint: disable=too-many-nested-blocks
maybe_before_assign = True
annotation_return = False
use_outer_definition = False
Expand Down Expand Up @@ -2014,8 +2013,13 @@ def _is_variable_violation(
for target in definition.targets
if isinstance(target, nodes.AssignName)
)
if defined_in_or_else:
break
elif isinstance(
definition, (nodes.ClassDef, nodes.FunctionDef)
):
defined_in_or_else = definition.name == node.name

if defined_in_or_else:
break

if not used_in_branch and not defined_in_or_else:
maybe_before_assign = True
Expand Down Expand Up @@ -2205,9 +2209,8 @@ def _loopvar_name(self, node: astroid.Name) -> None:
# scope lookup rules would need to be changed to return the initial
# assignment (which does not exist in code per se) as well as any later
# modifications.
# pylint: disable-next=too-many-boolean-expressions
if (
not astmts
not astmts # pylint: disable=too-many-boolean-expressions
or (
astmts[0].parent == astmts[0].root()
and astmts[0].parent.parent_of(node)
Expand Down Expand Up @@ -2337,6 +2340,10 @@ def _check_is_unused(
if name in comprehension_target_names:
return

# Ignore names in string literal type annotation.
if name in self._type_annotation_names:
return

argnames = node.argnames()
# Care about functions with unknown argument (builtins)
if name in argnames:
Expand Down Expand Up @@ -2900,6 +2907,41 @@ def _check_potential_index_error(
)
return

@utils.only_required_for_messages(
"unused-import",
"unused-variable",
)
def visit_const(self, node: nodes.Const) -> None:
"""Take note of names that appear inside string literal type annotations
unless the string is a parameter to typing.Literal.
"""
if node.pytype() != "builtins.str":
return
if not utils.is_node_in_type_annotation_context(node):
return
if not node.value.isidentifier():
try:
annotation = extract_node(node.value)
self._store_type_annotation_node(annotation)
except ValueError:
# e.g. node.value is white space
return
except astroid.AstroidSyntaxError:
# e.g. "?" or ":" in typing.Literal["?", ":"]
return

# Check if parent's or grandparent's first child is typing.Literal
parent = node.parent
if isinstance(parent, nodes.Tuple):
parent = parent.parent

if isinstance(parent, nodes.Subscript):
origin = next(parent.get_children(), None)
if origin is not None and utils.is_typing_literal(origin):
return

self._type_annotation_names.append(node.value)


def register(linter: PyLinter) -> None:
linter.register_checker(VariablesChecker(linter))
Loading