pylint-dev / pylint

It's not just a linter that annoys you!
https://pylint.readthedocs.io/en/latest/
GNU General Public License v2.0
5.27k stars 1.13k forks source link

Crash inferring a subclass of `typing.NamedTuple` #7268

Open Blind4Basics opened 2 years ago

Blind4Basics commented 2 years ago

Bug description

Hello,

As suggested in #7011 (message), I open a separate issue about that crash.

I managed to spot the exact part of the code that is causing the crash, so maybe that could help.

Here is the faulty snippet:

from typing import NamedTuple

class Color(NamedTuple):
    RED,CYAN,BLUE,BLACK,GREEN,WHITE = 31,36,34,30,32,37

Replacing this code with a declaration line by line resolved my problem:

class Color(NamedTuple):
    RED = 31
    CYAN = 36
    BLUE = 34
    BLACK = 30
    GREEN = 32
    WHITE = 37

I'm using VSC and pylint is running on each save, if that may matter....

Cheers

Configuration

No response

Command used

none (happened in VSC, checking the file on save)

When running `pylint ./create_project/utilities.py`, I get the same kind of stack trace than the one I found in your log `.txt` file

Pylint output

Traceback (most recent call last):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/inference_tip.py", line 37, in _inference_tip_cached
    result = _cache[func, node]
KeyError: (<function infer_typing_namedtuple_class at 0x7fbdf7d555a0>, <ClassDef.Color l.16 at 0x7fbdf7851120>)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/lint/pylinter.py", line 727, in _check_file
    check_astroid_module(ast_node)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/lint/pylinter.py", line 926, in check_astroid_module
    retval = self._check_astroid_module(
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/lint/pylinter.py", line 976, in _check_astroid_module
    walker.walk(node)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/utils/ast_walker.py", line 93, in walk
    self.walk(child)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/utils/ast_walker.py", line 90, in walk
    callback(astroid)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/checkers/base/basic_checker.py", line 498, in visit_functiondef
    self._check_dangerous_default(node)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/checkers/base/basic_checker.py", line 513, in _check_dangerous_default
    value = next(default.infer())
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/nodes/node_ng.py", line 168, in infer
    yield from self._infer(context=context, **kwargs)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/decorators.py", line 136, in raise_if_nothing_inferred
    yield next(generator)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/decorators.py", line 105, in wrapped
    for res in _func(node, context, **kwargs):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/inference.py", line 308, in infer_attribute
    for owner in self.expr.infer(context):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/nodes/node_ng.py", line 182, in infer
    for i, result in enumerate(generator):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/decorators.py", line 136, in raise_if_nothing_inferred
    yield next(generator)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/decorators.py", line 105, in wrapped
    for res in _func(node, context, **kwargs):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/bases.py", line 134, in _infer_stmts
    for inf in stmt.infer(context=context):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/nodes/node_ng.py", line 158, in infer
    results = list(self._explicit_inference(self, context, **kwargs))
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/inference_tip.py", line 44, in _inference_tip_cached
    result = _cache[func, node] = list(func(*args, **kwargs))
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/astroid/brain/brain_namedtuple_enum.py", line 483, in infer_typing_namedtuple_class
    generated_class_node.locals[attr] = class_node.locals[attr]
KeyError: 'tuple'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/lint/pylinter.py", line 684, in _check_files
    self._check_file(get_ast, check_astroid_module, file)
  File "/home/.../.cache/pypoetry/virtualenvs/create-project-wqycC8Vp-py3.10/lib/python3.10/site-packages/pylint/lint/pylinter.py", line 729, in _check_file
    raise astroid.AstroidError from e
astroid.exceptions.AstroidError

Expected behavior

'Shouldn't crash...

Pylint version

pylint 2.14.5
astroid 2.11.7
Python 3.10.4 (main, Jun 29 2022, 12:14:53) [GCC 11.2.0]

OS / Environment

Ubuntu 22.04

Additional dependencies

poetry 1.1.14, with the following toml file:

[tool.poetry.dependencies]
python = "^3.10"
pydantic = "^1.9.1"

[tool.poetry.dev-dependencies]
pylint = "^2.14.5"
pytest = "^7.1.2"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
jacobtylerwalls commented 2 years ago

Hey @Blind4Basics thanks for the report. I'm having trouble reproducing the issue.

$ tail typing-named-tuple.py 
from typing import NamedTuple

class Color(NamedTuple):
    RED,CYAN,BLUE,BLACK,GREEN,WHITE = 31,36,34,30,32,37

$ pylint --version
pylint 2.14.5
astroid 2.11.7
Python 3.10.1 (v3.10.1:2cd268a3a9, Dec  6 2021, 14:28:59) [Clang 13.0.0 (clang-1300.0.29.3)]

$ pylint typing-named-tuple.py 

************* Module typing-named-tuple
typing-named-tuple.py:5:0: C0305: Trailing newlines (trailing-newlines)
typing-named-tuple.py:1:0: C0114: Missing module docstring (missing-module-docstring)
typing-named-tuple.py:1:0: C0103: Module name "typing-named-tuple" doesn't conform to snake_case naming style (invalid-name)
typing-named-tuple.py:3:0: C0115: Missing class docstring (missing-class-docstring)

------------------------------------------------------------------
Your code has been rated at 0.00/10 (previous run: 0.00/10, +0.00)

Can you provide more steps to reproduce?

I noticed you experienced this issue in VS Code. VS Code might be using a different python interpreter than the one you invoked when running pylint --version.

Blind4Basics commented 2 years ago

Hello,

Sorry for the late answer, I didn't see the notification...

Yes, I'm using a venv in VSC and it often becomes a mess, for me. I'm not sure about how to make tails and heads of this. In my current environment, while the venv is activated, I still get the error. I tried the following in the console, if that may help:

(.venv) which pylint
[...root project here...]/.venv/bin/pylint

(.venv) pylint --version 
pylint 2.14.5
astroid 2.11.7
Python 3.10.4 (main, Aug  9 2022, 14:20:23) [GCC 11.2.0]

(.venv) which python
[...root project here...]/.venv/bin/python

I still get the same error when running pylint from the command line, targetting the file directly with:

(.venv) pylint .../file.py 

I tried from outside the venv as well, but since I didn't install pylint globally, I guess that's not relevant anyway since I had to target the pylint executable in the .venv/bin explicitely.

Note: I tried those procedure both from VSC's console and directly from a terminal. I get the very same results.


Now, about providing more steps, I guess I'll need to give the complete process I used to setup my machine. I'm starting from fresh Ubuntu 22.04 install, then I have several scripts installing a lot of stuff for me. The relevant parts are the following:

cd ~
sudo apt-get -y update && sudo apt -y upgrade
sudo apt install -y curl
source ~/.bashrc

# python specific parts (those are actually done in a subscript):

sudo ln -s /usr/bin/python3 /usr/bin/python

# "Install various libs needed for pyenv and python"
sudo apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev libxmlsec1-dev libxml2-dev python3-openssl

# "Install pyenv"
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# the below one is optionnal, to optimize pyenv executions. Don't care if it fails
cd ~/.pyenv && src/configure && make -C src

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.profile

# refresh sub script terminal
eval "$(cat ~/.bashrc | tail -n +10)"

# "Install last python version within pyenv, as global"
pyenv install 3.10.4 
pyenv global 3.10.4

python -m pip install --upgrade pip

# "Intstall poetry in the global env"
curl -sSL https://install.python-poetry.org | python3 -
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc

# refresh sub script terminal
eval "$(cat ~/.bashrc | tail -n +10)"

poetry config virtualenvs.in-project true

From there, I create a poetry project in the following manner:

cd [...project root...]
pyenv local 3.10.4
poetry init         #   => set pylint and pytest as dev dependencies 
poetry install
poetry shell

Then I write that python file we are talking about and "boom".

I believe that's the best I can do. Maybe there is something I do wrong in the installation/project setup part (I clearly don't master the details, there).

I hope this will help... Cheers


PS: I forgot to give my settings.json, for VSC;

{
    "python.linting.pylintEnabled": true,
    "python.linting.enabled": true,
    "python.testing.pytestArgs": [
        "tests"
    ],
    "python.testing.unittestEnabled": false,
    "python.testing.pytestEnabled": true
}

VSC's interpreter is set to the recommanded one: .venv/bin/python