4nds / pylint-quotes

Pylint plugin for checking the consistency of string quotes
MIT License
0 stars 0 forks source link

`AttributeError` (`Module.doc`) with release of `pylint==3.0.0` and `astroid==3.0.0` #2

Open 4nds opened 9 months ago

4nds commented 9 months ago

Bug description

When parsing the following utils.py:

"""Utilities for the example project."""

def do_something():
    '''Does something.'''
    return 'something'

def do_something_else():
    '''Does something else.

    Returns:
        str: A string of some sort.
    '''
    return "string1 " + 'string2'

The following error occurs with newer Pylint (>=3.0.0) and Astroid (>=3.0.0):

Traceback (most recent call last):
  File "d:\Python\Python311\Lib\site-packages\pylint\lint\pylinter.py", line 788, in _lint_file
    check_astroid_module(module)
  File "d:\Python\Python311\Lib\site-packages\pylint\lint\pylinter.py", line 1017, in check_astroid_module
    retval = self._check_astroid_module(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\Python\Python311\Lib\site-packages\pylint\lint\pylinter.py", line 1069, in _check_astroid_module
    walker.walk(node)
  File "d:\Python\Python311\Lib\site-packages\pylint\utils\ast_walker.py", line 91, in walk
    callback(astroid)
  File "C:\Users\ANDS\Documents\projects\pylint quotes\pylint-quotes\pylint_quotes\checker.py", line 111, in visit_module
    self._process_for_docstring(node, 'module')
  File "C:\Users\ANDS\Documents\projects\pylint quotes\pylint-quotes\pylint_quotes\checker.py", line 159, in _process_for_docstring
    if node.doc is not None:
       ^^^^^^^^
AttributeError: 'Module' object has no attribute 'doc'

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

Traceback (most recent call last):
  File "d:\Python\Python311\Lib\site-packages\pylint\lint\pylinter.py", line 752, in _lint_files
    self._lint_file(fileitem, module, check_astroid_module)
  File "d:\Python\Python311\Lib\site-packages\pylint\lint\pylinter.py", line 790, in _lint_file
    raise astroid.AstroidError from e
astroid.exceptions.AstroidError

Pylint version

pylint 3.0.3
astroid 3.0.3
Python 3.11.1 (tags/v3.11.1:a7a450f, Dec  6 2022, 19:58:39) [MSC v.1934 64 bit (AMD64)]

OS / Environment

win32 (Windows)

Script used

I used the following script to produce the error for debugging purposes, but the same error occurs when running Pylint in command line or using Pylint extension in Visual Studio Code:

"""File for testing pylint."""

import pylint.lint

def check_file(file_path: str) -> int:
    """Function checking file with pylint."""
    if not file_path.endswith('.py'):
        return 0

    pylint_opts = [
        "--load-plugins=pylint_quotes",
        "--string-quote=single-avoid-escape",
        "--triple-quote=single",
        "--docstring-quote=double",
    ]
    runner = pylint.lint.Run(pylint_opts + [file_path], exit=False)
    return runner.linter.msg_status

check_file(r'pylint-quotes/example/foo/utils.py')
4nds commented 9 months ago

The error happens because node has no attribute doc,

https://github.com/4nds/pylint-quotes/blob/c9aae00800289e7bf89a13ba81950334aff5668f/pylint_quotes/checker.py#L159

variable node is object of class astroid.nodes.Module,

astroid/astroid/nodes/scoped_nodes/scoped_nodes.py

class Module(LocalsDictNodeNG):
    """Class representing an :class:`ast.Module` node.

and class astroid.nodes.Module since Astroid version 3.0.0 no longer contains doc attribute which was depreciated since Astroid 2.11.0,

Accessing the doc attribute of nodes.Module, nodes.ClassDef, and nodes.FunctionDef has been deprecated in favour of the doc_node attribute. Note: doc_node is an (optional) nodes.Const whereas doc was an (optional) str.

astroid/astroid/nodes/scoped_nodes/scoped_nodes.py

    @property
    def doc(self) -> str | None:
        """The module docstring."""
        warnings.warn(
            "The 'Module.doc' attribute is deprecated, "
            "use 'Module.doc_node' instead.",
            DeprecationWarning,
            stacklevel=2,
        )
        return self._doc

and later removed in Astroid 3.0.0,

Remove deprecated doc attribute for Module, ClassDef, and FunctionDef. Use the doc_node attribute instead.

Like the deprecation warning says solution is to use doc_node attribute instead of doc attribute. So instead of node.doc in

https://github.com/4nds/pylint-quotes/blob/c9aae00800289e7bf89a13ba81950334aff5668f/pylint_quotes/checker.py#L159

we need to use node.doc_node.

Remark: Even though type of `doc` attribute is `str` and type of `doc_node` is `astroid.nodes.Const`, [astroid/astroid/nodes/scoped_nodes/scoped_nodes.py](https://github.com/pylint-dev/astroid/blob/c633af204678a69708857af0793b2a4ca11107b0/astroid/nodes/scoped_nodes/scoped_nodes.py#L233-L309) ```python @decorators_mod.deprecate_arguments(doc="Use the postinit arg 'doc_node' instead") def __init__( self, name: str, doc: str | None = None, file: str | None = None, path: list[str] | None = None, package: bool | None = None, parent: None = None, pure_python: bool | None = True, ) -> None: ⋮ ⋮ self._doc = doc """The module docstring.""" ⋮ ⋮ self.doc_node: Const | None = None """The doc node associated with this node.""" ⋮ ⋮ def postinit(self, body=None, *, doc_node: Const | None = None): """Do some setup after initialisation. :param body: The contents of the module. :type body: list(NodeNG) or None :param doc_node: The doc node associated with this node. """ self.body = body self.doc_node = doc_node if doc_node: self._doc = doc_node.value ``` both atributes are optional, `doc_node` is an (optional) `nodes.Const` whereas `doc` is (optional) `str`, and in cases when there is no docstring both `doc` and `doc_node` wil be `None`. So in our [case](https://github.com/4nds/pylint-quotes/blob/c9aae00800289e7bf89a13ba81950334aff5668f/pylint_quotes/checker.py#L159) it is enough to replace `doc` with `doc_node`.