pylint
pylint copied to clipboard
pylint crashed with a ``AstroidError`` (astroid.exceptions.ParentMissingError)
Bug description
When trying to lint a file that contain the DeclarativeBase of the recent SQLAlchemy 2.0 (beta), it fails with an astroid.exceptions.ParentMissingError: Parent not found on <Const.str l.None at 0x189844d3730>.
error. I was able to pin point the issue with the new sqlalchemy.orm.DeclarativeBase
.
I understand this is most probably due to the new SQLAlchemy 2.0, but since the traceback point to pylint, I created to issue here. Maybe some guys from SQLAlchemy could help out here too? @CaselIT @zzzeek (hopefully that will ping them!)
Code that makes pylint crash
The code below is based on the migration guide and the declarative mixins. The only difference I made is to put the mixin directly in the base.
# pylint: disable=missing-docstring
from sqlalchemy.orm import DeclarativeBase, declared_attr
class Base(DeclarativeBase):
@classmethod
@declared_attr.directive
def __tablename__(cls):
return cls.__name__.lower()
Stacktrace
Traceback (most recent call last):
File "[project_root].venv\lib\site-packages\pylint\lint\pylinter.py", line 790, in _lint_file
check_astroid_module(module)
File "[project_root].venv\lib\site-packages\pylint\lint\pylinter.py", line 1060, in check_astroid_module
retval = self._check_astroid_module(
File "[project_root].venv\lib\site-packages\pylint\lint\pylinter.py", line 1110, in _check_astroid_module
walker.walk(node)
File "[project_root].venv\lib\site-packages\pylint\utils\ast_walker.py", line 93, in walk
self.walk(child)
File "[project_root].venv\lib\site-packages\pylint\utils\ast_walker.py", line 93, in walk
self.walk(child)
File "[project_root].venv\lib\site-packages\pylint\utils\ast_walker.py", line 90, in walk
callback(astroid)
File "[project_root].venv\lib\site-packages\pylint\checkers\classes\special_methods_checker.py", line 183, in visit_functiondef
inferred = _safe_infer_call_result(node, node)
File "[project_root].venv\lib\site-packages\pylint\checkers\classes\special_methods_checker.py", line 42, in _safe_infer_call_result
value = next(inferit)
File "[project_root].venv\lib\site-packages\astroid\nodes\scoped_nodes\scoped_nodes.py", line 1749, in infer_call_result
yield from returnnode.value.infer(context)
File "[project_root].venv\lib\site-packages\astroid\nodes\node_ng.py", line 169, in infer
yield from self._infer(context=context, **kwargs)
File "[project_root].venv\lib\site-packages\astroid\decorators.py", line 140, in raise_if_nothing_inferred
yield next(generator)
File "[project_root].venv\lib\site-packages\astroid\decorators.py", line 109, in wrapped
for res in _func(node, context, **kwargs):
File "[project_root].venv\lib\site-packages\astroid\inference.py", line 255, in infer_call
for callee in self.func.infer(context):
File "[project_root].venv\lib\site-packages\astroid\nodes\node_ng.py", line 182, in infer
for i, result in enumerate(self._infer(context=context, **kwargs)):
File "[project_root].venv\lib\site-packages\astroid\decorators.py", line 140, in raise_if_nothing_inferred
yield next(generator)
File "[project_root].venv\lib\site-packages\astroid\decorators.py", line 109, in wrapped
for res in _func(node, context, **kwargs):
File "[project_root].venv\lib\site-packages\astroid\inference.py", line 343, in infer_attribute
for owner in self.expr.infer(context):
File "[project_root].venv\lib\site-packages\astroid\nodes\node_ng.py", line 182, in infer
for i, result in enumerate(self._infer(context=context, **kwargs)):
File "[project_root].venv\lib\site-packages\astroid\decorators.py", line 140, in raise_if_nothing_inferred
yield next(generator)
File "[project_root].venv\lib\site-packages\astroid\decorators.py", line 109, in wrapped
for res in _func(node, context, **kwargs):
File "[project_root].venv\lib\site-packages\astroid\inference.py", line 352, in infer_attribute
yield from owner.igetattr(self.attrname, context)
File "[project_root].venv\lib\site-packages\astroid\nodes\scoped_nodes\scoped_nodes.py", line 2646, in igetattr
first_scope = first_attr.scope()
File "[project_root].venv\lib\site-packages\astroid\nodes\node_ng.py", line 359, in scope
raise ParentMissingError(target=self)
astroid.exceptions.ParentMissingError: Parent not found on <Const.str l.None at 0x189844d3730>.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "[project_root].venv\lib\site-packages\pylint\lint\pylinter.py", line 755, in _lint_files
self._lint_file(fileitem, module, check_astroid_module)
File "[project_root].venv\lib\site-packages\pylint\lint\pylinter.py", line 792, in _lint_file
raise astroid.AstroidError from e
astroid.exceptions.AstroidError
Code that works
Having the mixin code not in the Base seems to resolve the issue.
# pylint: disable=missing-docstring
from sqlalchemy.orm import DeclarativeBase, Mapped, declared_attr, mapped_column
class Base(DeclarativeBase):
pass
class CommonMixin:
@classmethod
@declared_attr.directive
def __tablename__(cls) -> str:
return cls.__name__.lower()
id: Mapped[int] = mapped_column(primary_key=True)
So does getting rid of DeclarativeBase
# pylint: disable=missing-docstring
class Base:
@classmethod
def __tablename__(cls):
"""My Docstring"""
return cls.__name__.lower()
Configuration
No response
Command used
pylint test.py
Pylint output
************* Module test
test.py:1:0: F0002: test.py: Fatal error while checking 'test.py'. Please open an issue in our bug tracker so we address this. There is a pre-filled template that you can use in '[...]'. (astroid-error)
Expected behavior
No issues found.
Pylint version
pylint 2.15.5
astroid 2.12.12
Python 3.10.5 (tags/v3.10.5:f377153, Jun 6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)]
OS / Environment
Windows 10 Poetry
Additional dependencies
sqlalchemy = {version = "^2.0.0b2", allow-prereleases = true}
definitely on pylint side, we run many code quality tools on sqlalchemy including flake8 with lots of extensions, mypy, pyright, pylance, black, and others.
pylint 2.15.5 reproduces the issue, while an older version I had installed, 2.11.1, does not:
$ pylint test3.py
************* Module test3
test3.py:9:0: C0304: Final newline missing (missing-final-newline)
test3.py:5:0: R0903: Too few public methods (1/2) (too-few-public-methods)
------------------------------------------------------------------
Your code has been rated at 5.00/10 (previous run: 5.00/10, +0.00)
I had a very similar issue in #9446 and simply removing the @classmethod
worked for me:
class UUIDAuditBase(DeclarativeBase):
"""Base db model that includes id, created_at, and update_at."""
id: Mapped[UUID] = mapped_column(primary_key=True)
created_at: Mapped[DateTime] = mapped_column(
DateTime(timezone=True),
default=functions.now(),
)
updated_at: Mapped[DateTime] = mapped_column(
DateTime(timezone=True),
default=functions.now(),
onupdate=functions.now(),
)
@declared_attr.directive
def __tablename__(cls) -> str: # noqa: N805
"""Set default table name as the lowercase version of the class name."""
return cls.__name__.lower()