Skip to content

Commit

Permalink
Update astroid to 2.12.0
Browse files Browse the repository at this point in the history
Prevent `unused-import` for `six.with_metaclass`

Adjust `pyreverse` test results accounting for `tests` as a namespace package

Update expected result for `func_w0401_package`

Update `contributors-txt` to 0.9.0

Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
Co-authored-by: Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
  • Loading branch information
3 people committed Jul 12, 2022
1 parent eb57ded commit e8043f9
Show file tree
Hide file tree
Showing 20 changed files with 85 additions and 69 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ on:
pull_request: ~

env:
# Also change CACHE_VERSION in the other workflows
CACHE_VERSION: 8
CACHE_VERSION: 1
DEFAULT_PYTHON: "3.10"
PRE_COMMIT_CACHE: ~/.cache/pre-commit

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

env:
# Also change CACHE_VERSION in the CI workflow
CACHE_VERSION: 6
CACHE_VERSION: 1

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 @@ -13,7 +13,7 @@ on:
- completed

env:
CACHE_VERSION: 2
CACHE_VERSION: 1

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 @@ -15,7 +15,7 @@ concurrency:
cancel-in-progress: true

env:
CACHE_VERSION: 2
CACHE_VERSION: 1

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 @@ -24,7 +24,7 @@ concurrency:
cancel-in-progress: true

env:
CACHE_VERSION: 2
CACHE_VERSION: 1

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

env:
# Also change CACHE_VERSION in the other workflows
CACHE_VERSION: 7
CACHE_VERSION: 1

jobs:
tests-linux:
Expand Down
13 changes: 8 additions & 5 deletions doc/user_guide/usage/run.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,25 @@ Pylint is meant to be called from the command line. The usage is ::

pylint [options] modules_or_packages

By default the ``pylint`` command only accepts a list of python modules and packages. Using a
directory which is not a package results in an error::
By default the ``pylint`` command only accepts a list of python modules and packages.
On versions below 2.15, specifying a directory that is not an explicit package
(with ``__init__.py``) results in an error::

pylint mydir
************* Module mydir
mydir/__init__.py:1:0: F0010: error while code parsing: Unable to load file mydir/__init__.py:
[Errno 2] No such file or directory: 'mydir/__init__.py' (parse-error)

When ``--recursive=y`` option is used, modules and packages are also accepted as parameters::
When the ``--recursive=y`` option is used, modules and packages are also accepted as parameters::

pylint --recursive=y mydir mymodule mypackage

This option makes ``pylint`` attempt to discover all modules (files ending with ``.py`` extension)
and all packages (all directories containing a ``__init__.py`` file).
and all explicit packages (all directories containing a ``__init__.py`` file).
As of version 2.15, ``pylint`` will also discover namespace packages but there are some edge
cases still under development (where you might still find ``--recursive=y`` useful).

Pylint **will not import** this package or module, though uses Python internals
Pylint **will not import** this package or module, but it does use Python internals
to locate them and as such is subject to the same rules and configuration.
You should pay attention to your ``PYTHONPATH``, since it is a common error
to analyze an installed version of a module instead of the development version.
Expand Down
5 changes: 5 additions & 0 deletions doc/whatsnew/2/2.15/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
Summary -- Release highlights
=============================

* We improved ``pylint``'s handling of namespace packages. More packages should be
linted without resorting to using the ``-recursive=y`` option.


New checkers
============
Expand Down Expand Up @@ -86,6 +89,8 @@ Other Changes

Closes #6953

* Update ``astroid`` to 2.12.


Internal changes
================
Expand Down
4 changes: 3 additions & 1 deletion pylint/checkers/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,9 @@ def _get_imported_module(self, importnode, modname):
return None
self.add_message("relative-beyond-top-level", node=importnode)
except astroid.AstroidSyntaxError as exc:
message = f"Cannot import {modname!r} due to syntax error {str(exc.error)!r}" # pylint: disable=no-member; false positive
message = (
f"Cannot import {modname!r} due to syntax error {str(exc.error)!r}"
)
self.add_message("syntax-error", line=importnode.lineno, args=message)

except astroid.AstroidBuildingError:
Expand Down
19 changes: 17 additions & 2 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -1137,9 +1137,24 @@ def visit_classdef(self, node: nodes.ClassDef) -> None:
"""Visit class: update consumption analysis variable."""
self._to_consume.append(NamesConsumer(node, "class"))

def leave_classdef(self, _: nodes.ClassDef) -> None:
def leave_classdef(self, node: nodes.ClassDef) -> None:
"""Leave class: update consumption analysis variable."""
# do not check for not used locals here (no sense)
# Check for hidden ancestor names
# e.g. "six" in: Class X(six.with_metaclass(ABCMeta, object)):
for name_node in node.nodes_of_class(nodes.Name):
if (
isinstance(name_node.parent, nodes.Call)
and isinstance(name_node.parent.func, nodes.Attribute)
and isinstance(name_node.parent.func.expr, nodes.Name)
):
hidden_name_node = name_node.parent.func.expr
for consumer in self._to_consume:
if hidden_name_node.name in consumer.to_consume:
consumer.mark_as_consumed(
hidden_name_node.name,
consumer.to_consume[hidden_name_node.name],
)
break
self._to_consume.pop()

def visit_lambda(self, node: nodes.Lambda) -> None:
Expand Down
1 change: 0 additions & 1 deletion pylint/lint/pylinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,6 @@ def get_ast(
data, modname, filepath
)
except astroid.AstroidSyntaxError as ex:
# pylint: disable=no-member
self.add_message(
"syntax-error",
line=getattr(ex.error, "lineno", 0),
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ dependencies = [
"dill>=0.2",
"platformdirs>=2.2.0",
# Also upgrade requirements_test_min.txt if you are bumping astroid.
# Pinned to dev of next minor update to allow editable installs,
# Pinned to dev of second minor update to allow editable installs and fix primer issues,
# see https://github.com/PyCQA/astroid/issues/1341
"astroid>=2.11.6,<=2.12.0-dev0",
"astroid>=2.12.2,<=2.14.0-dev0",
"isort>=4.2.5,<6",
"mccabe>=0.6,<0.8",
"tomli>=1.1.0;python_version<'3.11'",
Expand Down
2 changes: 1 addition & 1 deletion requirements_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ coveralls~=3.3
coverage~=6.4
pre-commit~=2.20
tbump~=6.9.0
contributors-txt>=0.7.3
contributors-txt>=0.9.0
pytest-cov~=3.0
pytest-profiling~=1.7
pytest-xdist~=2.5
Expand Down
4 changes: 2 additions & 2 deletions requirements_test_min.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-e .[testutils,spelling]
# astroid dependency is also defined in setup.cfg
astroid==2.11.6 # Pinned to a specific version for tests
# astroid dependency is also defined in pyproject.toml
astroid==2.12.2 # Pinned to a specific version for tests
typing-extensions~=4.3
pytest~=7.1
pytest-benchmark~=3.4
Expand Down
5 changes: 5 additions & 0 deletions tests/functional/u/unused/unused_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import xml.etree # [unused-import]
import xml.sax # [unused-import]
import os.path as test # [unused-import]
from abc import ABCMeta
from sys import argv as test2 # [unused-import]
from sys import flags # [unused-import]
# +1:[unused-import,unused-import]
from collections import deque, OrderedDict, Counter
import re, html.parser # [unused-import]
DATA = Counter()
# pylint: disable=self-assigning-variable
import six
from fake import SomeName, SomeOtherName # [unused-import]
class SomeClass(object):
SomeName = SomeName # https://bitbucket.org/logilab/pylint/issue/475
Expand Down Expand Up @@ -87,3 +89,6 @@ def blop(self):
TYPE_CHECKING = False
if TYPE_CHECKING:
import zoneinfo

class WithMetaclass(six.with_metaclass(ABCMeta, object)):
pass
22 changes: 11 additions & 11 deletions tests/functional/u/unused/unused_import.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
unused-import:3:0:3:16::Unused import xml.etree:UNDEFINED
unused-import:4:0:4:14::Unused import xml.sax:UNDEFINED
unused-import:5:0:5:22::Unused os.path imported as test:UNDEFINED
unused-import:6:0:6:29::Unused argv imported from sys as test2:UNDEFINED
unused-import:7:0:7:21::Unused flags imported from sys:UNDEFINED
unused-import:9:0:9:51::Unused OrderedDict imported from collections:UNDEFINED
unused-import:9:0:9:51::Unused deque imported from collections:UNDEFINED
unused-import:10:0:10:22::Unused import re:UNDEFINED
unused-import:13:0:13:40::Unused SomeOtherName imported from fake:UNDEFINED
unused-import:48:0:48:9::Unused import os:UNDEFINED
unused-import:79:4:79:19::Unused import unittest:UNDEFINED
unused-import:81:4:81:15::Unused import uuid:UNDEFINED
unused-import:83:4:83:19::Unused import warnings:UNDEFINED
unused-import:85:4:85:21::Unused import compileall:UNDEFINED
unused-import:7:0:7:29::Unused argv imported from sys as test2:UNDEFINED
unused-import:8:0:8:21::Unused flags imported from sys:UNDEFINED
unused-import:10:0:10:51::Unused OrderedDict imported from collections:UNDEFINED
unused-import:10:0:10:51::Unused deque imported from collections:UNDEFINED
unused-import:11:0:11:22::Unused import re:UNDEFINED
unused-import:15:0:15:40::Unused SomeOtherName imported from fake:UNDEFINED
unused-import:50:0:50:9::Unused import os:UNDEFINED
unused-import:81:4:81:19::Unused import unittest:UNDEFINED
unused-import:83:4:83:15::Unused import uuid:UNDEFINED
unused-import:85:4:85:19::Unused import warnings:UNDEFINED
unused-import:87:4:87:21::Unused import compileall:UNDEFINED
2 changes: 1 addition & 1 deletion tests/messages/func_w0401_package.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
R: 1: Cyclic import (input.func_w0401_package.all_the_things -> input.func_w0401_package.thing2)
R: 1: Cyclic import (tests.input.func_w0401_package.all_the_things -> tests.input.func_w0401_package.thing2)
W: 8: Using a conditional statement with a constant value
15 changes: 11 additions & 4 deletions tests/pyreverse/test_diadefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
from pylint.pyreverse.diagrams import DiagramEntity, Relationship
from pylint.pyreverse.inspector import Linker, Project
from pylint.testutils.pyreverse import PyreverseConfig
from pylint.testutils.utils import _test_cwd

HERE = Path(__file__)
TESTS = HERE.parent.parent


def _process_classes(classes: list[DiagramEntity]) -> list[tuple[bool, str]]:
Expand All @@ -50,7 +54,8 @@ def HANDLER(default_config: PyreverseConfig) -> DiadefsHandler:

@pytest.fixture(scope="module")
def PROJECT(get_project):
return get_project("data")
with _test_cwd(TESTS):
yield get_project("data")


def test_option_values(
Expand Down Expand Up @@ -100,15 +105,17 @@ class TestDefaultDiadefGenerator:
("specialization", "Specialization", "Ancestor"),
]

def test_exctract_relations(
self, HANDLER: DiadefsHandler, PROJECT: Project
) -> None:
# https://github.com/PyCQA/pylint/issues/2763
@pytest.mark.xfail
def test_extract_relations(self, HANDLER: DiadefsHandler, PROJECT: Project) -> None:
"""Test extract_relations between classes."""
cd = DefaultDiadefGenerator(Linker(PROJECT), HANDLER).visit(PROJECT)[1]
cd.extract_relationships()
relations = _process_relations(cd.relationships)
assert relations == self._should_rels

# https://github.com/PyCQA/pylint/issues/2763
@pytest.mark.xfail
def test_functional_relation_extraction(
self, default_config: PyreverseConfig, get_project: Callable
) -> None:
Expand Down
18 changes: 12 additions & 6 deletions tests/pyreverse/test_inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,28 @@
from __future__ import annotations

import os
from collections.abc import Callable
from collections.abc import Callable, Generator
from pathlib import Path

import astroid
import pytest
from astroid import nodes

from pylint.pyreverse import inspector
from pylint.pyreverse.inspector import Project
from pylint.testutils.utils import _test_cwd

HERE = Path(__file__)
TESTS = HERE.parent.parent


@pytest.fixture
def project(get_project: Callable) -> Project:
project = get_project("data", "data")
linker = inspector.Linker(project)
linker.visit(project)
return project
def project(get_project: Callable) -> Generator[Project, None, None]:
with _test_cwd(TESTS):
project = get_project("data", "data")
linker = inspector.Linker(project)
linker.visit(project)
yield project


def test_class_implements(project: Project) -> None:
Expand Down
25 changes: 1 addition & 24 deletions tests/test_self.py
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ def test_regression_parallel_mode_without_filepath(self) -> None:
path = join(
HERE, "regrtest_data", "regression_missing_init_3564", "subdirectory/"
)
self._test_output([path, "-j2"], expected_output="No such file or directory")
self._test_output([path, "-j2"], expected_output="")

def test_output_file_valid_path(self, tmpdir: LocalPath) -> None:
path = join(HERE, "regrtest_data", "unused_variable.py")
Expand Down Expand Up @@ -1210,13 +1210,6 @@ def test_max_inferred_for_complicated_class_hierarchy() -> None:
# Error code should not include bit-value 1 for crash
assert not ex.value.code % 2

def test_regression_recursive(self):
"""Tests if error is raised when linter is executed over directory not using --recursive=y"""
self._test_output(
[join(HERE, "regrtest_data", "directory", "subdirectory"), "--recursive=n"],
expected_output="No such file or directory",
)

def test_recursive(self):
"""Tests if running linter over directory using --recursive=y"""
self._runtest(
Expand Down Expand Up @@ -1333,22 +1326,6 @@ def test_ignore_path_recursive_current_dir(self) -> None:
code=0,
)

def test_regression_recursive_current_dir(self):
with _test_sys_path():
# pytest is including directory HERE/regrtest_data to sys.path which causes
# astroid to believe that directory is a package.
sys.path = [
path
for path in sys.path
if not os.path.basename(path) == "regrtest_data"
]
with _test_cwd():
os.chdir(join(HERE, "regrtest_data", "directory"))
self._test_output(
["."],
expected_output="No such file or directory",
)


class TestCallbackOptions:
"""Test for all callback options we support."""
Expand Down

0 comments on commit e8043f9

Please sign in to comment.