Skip to content

Commit

Permalink
Merge branch 'main' into patch-2
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre-Sassoulas committed Dec 13, 2022
2 parents ef165e7 + c61bc76 commit f5f8c4c
Show file tree
Hide file tree
Showing 30 changed files with 273 additions and 90 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/changelog.yml
Expand Up @@ -28,7 +28,7 @@ jobs:
fetch-depth: 0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/checks.yaml
Expand Up @@ -36,7 +36,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down Expand Up @@ -90,7 +90,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down Expand Up @@ -139,7 +139,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down Expand Up @@ -171,7 +171,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/primer-test.yaml
Expand Up @@ -38,7 +38,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -77,7 +77,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -113,7 +113,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer_comment.yaml
Expand Up @@ -37,7 +37,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer_run_main.yaml
Expand Up @@ -35,7 +35,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primer_run_pr.yaml
Expand Up @@ -46,7 +46,7 @@ jobs:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Expand Up @@ -23,7 +23,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ env.DEFAULT_PYTHON }}
check-latest: true
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/tests.yaml
Expand Up @@ -35,7 +35,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -91,7 +91,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -136,7 +136,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -194,7 +194,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -240,7 +240,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down Expand Up @@ -284,7 +284,7 @@ jobs:
uses: actions/checkout@v3.1.0
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v4.3.0
uses: actions/setup-python@v4.3.1
with:
python-version: ${{ matrix.python-version }}
check-latest: true
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Expand Up @@ -39,12 +39,12 @@ repos:
args: [--py37-plus]
exclude: *fixtures
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.11.1
hooks:
- id: isort
exclude: doc/data/messages/(r/reimported|w/wrong-import-order|u/ungrouped-imports|m/misplaced-future|m/multiple-imports)/bad.py
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 22.12.0
hooks:
- id: black
args: [--safe, --quiet]
Expand All @@ -58,7 +58,7 @@ repos:
hooks:
- id: flake8
additional_dependencies:
[flake8-bugbear==22.10.27, flake8-typing-imports==1.14.0]
[flake8-bugbear==22.12.6, flake8-typing-imports==1.14.0]
exclude: *fixtures
- repo: local
hooks:
Expand Down
2 changes: 1 addition & 1 deletion doc/requirements.txt
Expand Up @@ -2,5 +2,5 @@ Sphinx==5.3.0
sphinx-reredirects<1
myst-parser~=0.18
towncrier~=22.8
furo==2022.9.29
furo==2022.12.7
-e .
4 changes: 4 additions & 0 deletions doc/whatsnew/fragments/3899.bugfix
@@ -0,0 +1,4 @@
Pylint will no longer deadlock if a parallel job is killed but fail
immediately instead.

Closes #3899
4 changes: 4 additions & 0 deletions doc/whatsnew/fragments/5327.false_positive
@@ -0,0 +1,4 @@
Fix false-positive for ``used-before-assignment`` in pattern matching
with a guard.

Closes #5327
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/7788.false_negative
@@ -0,0 +1,3 @@
``no-else-return`` or ``no-else-raise`` will be emitted if ``except`` block always returns or raises.

Closes #7788
43 changes: 36 additions & 7 deletions pylint/checkers/refactoring/refactoring_checker.py
Expand Up @@ -73,6 +73,16 @@ def _if_statement_is_always_returning(
return any(isinstance(node, returning_node_class) for node in if_node.body)


def _except_statement_is_always_returning(
node: nodes.TryExcept, returning_node_class: nodes.NodeNG
) -> bool:
"""Detect if all except statements return."""
return all(
any(isinstance(child, returning_node_class) for child in handler.body)
for handler in node.handlers
)


def _is_trailing_comma(tokens: list[tokenize.TokenInfo], index: int) -> bool:
"""Check if the given token is a trailing comma.
Expand Down Expand Up @@ -531,7 +541,7 @@ def _is_bool_const(node: nodes.Return | nodes.Assign) -> bool:
node.value.value, bool
)

def _is_actual_elif(self, node: nodes.If) -> bool:
def _is_actual_elif(self, node: nodes.If | nodes.TryExcept) -> bool:
"""Check if the given node is an actual elif.
This is a problem we're having with the builtin ast module,
Expand Down Expand Up @@ -642,10 +652,14 @@ def leave_module(self, _: nodes.Module) -> None:
)
self._init()

@utils.only_required_for_messages("too-many-nested-blocks")
def visit_tryexcept(self, node: nodes.TryExcept) -> None:
@utils.only_required_for_messages("too-many-nested-blocks", "no-else-return")
def visit_tryexcept(self, node: nodes.TryExcept | nodes.TryFinally) -> None:
self._check_nested_blocks(node)

if isinstance(node, nodes.TryExcept):
self._check_superfluous_else_return(node)
self._check_superfluous_else_raise(node)

visit_tryfinally = visit_tryexcept
visit_while = visit_tryexcept

Expand Down Expand Up @@ -707,23 +721,38 @@ def visit_with(self, node: nodes.With) -> None:
self._check_redefined_argument_from_local(name)

def _check_superfluous_else(
self, node: nodes.If, msg_id: str, returning_node_class: nodes.NodeNG
self,
node: nodes.If | nodes.TryExcept,
msg_id: str,
returning_node_class: nodes.NodeNG,
) -> None:
if isinstance(node, nodes.TryExcept) and isinstance(
node.parent, nodes.TryFinally
):
# Not interested in try/except/else/finally statements.
return

if not node.orelse:
# Not interested in if statements without else.
# Not interested in if/try statements without else.
return

if self._is_actual_elif(node):
# Not interested in elif nodes; only if
return

if _if_statement_is_always_returning(node, returning_node_class):
if (
isinstance(node, nodes.If)
and _if_statement_is_always_returning(node, returning_node_class)
) or (
isinstance(node, nodes.TryExcept)
and _except_statement_is_always_returning(node, returning_node_class)
):
orelse = node.orelse[0]
if (orelse.lineno, orelse.col_offset) in self._elifs:
args = ("elif", 'remove the leading "el" from "elif"')
else:
args = ("else", 'remove the "else" and de-indent the code inside it')
self.add_message(msg_id, node=node, args=args)
self.add_message(msg_id, node=node, args=args, confidence=HIGH)

def _check_superfluous_else_return(self, node: nodes.If) -> None:
return self._check_superfluous_else(
Expand Down
20 changes: 9 additions & 11 deletions pylint/checkers/variables.py
Expand Up @@ -900,21 +900,16 @@ def _defines_name_raises_or_returns(name: str, node: nodes.NodeNG) -> bool:
if isinstance(node, nodes.Assign):
for target in node.targets:
for elt in utils.get_all_elements(target):
if isinstance(elt, nodes.Starred):
elt = elt.value
if isinstance(elt, nodes.AssignName) and elt.name == name:
return True
if isinstance(node, nodes.If):
# Check for assignments inside the test
if isinstance(node.test, nodes.NamedExpr) and node.test.target.name == name:
if any(
child_named_expr.target.name == name
for child_named_expr in node.nodes_of_class(nodes.NamedExpr)
):
return True
if isinstance(node.test, nodes.Call):
for arg_or_kwarg in node.test.args + [
kw.value for kw in node.test.keywords
]:
if (
isinstance(arg_or_kwarg, nodes.NamedExpr)
and arg_or_kwarg.target.name == name
):
return True
return False

@staticmethod
Expand Down Expand Up @@ -2139,6 +2134,7 @@ def _is_variable_violation(
nodes.AugAssign,
nodes.Expr,
nodes.Return,
nodes.Match,
),
)
and VariablesChecker._maybe_used_and_assigned_at_once(defstmt)
Expand Down Expand Up @@ -2239,6 +2235,8 @@ def _maybe_used_and_assigned_at_once(defstmt: nodes.Statement) -> bool:
"""Check if `defstmt` has the potential to use and assign a name in the
same statement.
"""
if isinstance(defstmt, nodes.Match):
return any(case.guard for case in defstmt.cases)
if isinstance(defstmt.value, nodes.BaseContainer) and defstmt.value.elts:
# The assignment must happen as part of the first element
# e.g. "assert (x:= True), x"
Expand Down
21 changes: 11 additions & 10 deletions pylint/lint/parallel.py
Expand Up @@ -23,19 +23,23 @@
except ImportError:
multiprocessing = None # type: ignore[assignment]

try:
from concurrent.futures import ProcessPoolExecutor
except ImportError:
ProcessPoolExecutor = None # type: ignore[assignment,misc]

if TYPE_CHECKING:
from pylint.lint import PyLinter

# PyLinter object used by worker processes when checking files using multiprocessing
# PyLinter object used by worker processes when checking files using parallel mode
# should only be used by the worker processes
_worker_linter: PyLinter | None = None


def _worker_initialize(
linter: bytes, arguments: None | str | Sequence[str] = None
) -> None:
"""Function called to initialize a worker for a Process within a multiprocessing
Pool.
"""Function called to initialize a worker for a Process within a concurrent Pool.
:param linter: A linter-class (PyLinter) instance pickled with dill
:param arguments: File or module name(s) to lint and to be added to sys.path
Expand Down Expand Up @@ -137,9 +141,9 @@ def check_parallel(
# is identical to the linter object here. This is required so that
# a custom PyLinter object can be used.
initializer = functools.partial(_worker_initialize, arguments=arguments)
with multiprocessing.Pool(
jobs, initializer=initializer, initargs=[dill.dumps(linter)]
) as pool:
with ProcessPoolExecutor(
max_workers=jobs, initializer=initializer, initargs=(dill.dumps(linter),)
) as executor:
linter.open()
all_stats = []
all_mapreduce_data: defaultdict[
Expand All @@ -158,7 +162,7 @@ def check_parallel(
stats,
msg_status,
mapreduce_data,
) in pool.imap_unordered(_worker_check_single_file, files):
) in executor.map(_worker_check_single_file, files):
linter.file_state.base_name = base_name
linter.file_state._is_base_filestate = False
linter.set_current_module(module, file_path)
Expand All @@ -168,8 +172,5 @@ def check_parallel(
all_mapreduce_data[worker_idx].append(mapreduce_data)
linter.msg_status |= msg_status

pool.close()
pool.join()

_merge_mapreduce_data(linter, all_mapreduce_data)
linter.stats = merge_stats([linter.stats] + all_stats)

0 comments on commit f5f8c4c

Please sign in to comment.