nelfin / pylint-protobuf

A plugin for making Pylint aware of the fields of protobuf-generated classes
MIT License
29 stars 12 forks source link

'Subscript' object has no attribute 'name' when running on directory module #3

Closed endafarrell closed 5 years ago

endafarrell commented 5 years ago
Traceback (most recent call last):
  File "/Users/efarrell/anaconda/envs/LG-py37/bin/pylint", line 10, in <module>
    sys.exit(run_pylint())
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/__init__.py", line 20, in run_pylint
    Run(sys.argv[1:])
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/lint.py", line 1608, in __init__
    linter.check(args)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/lint.py", line 938, in check
    self._do_check(files_or_modules)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/lint.py", line 1071, in _do_check
    self.check_astroid_module(ast_node, walker, rawcheckers, tokencheckers)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/lint.py", line 1154, in check_astroid_module
    walker.walk(ast_node)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/utils.py", line 1269, in walk
    self.walk(child)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/utils.py", line 1269, in walk
    self.walk(child)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/utils.py", line 1269, in walk
    self.walk(child)
  [Previous line repeated 2 more times]
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/utils.py", line 1266, in walk
    cb(astroid)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint_protobuf/__init__.py", line 142, in visit_call
    name = func.name
AttributeError: 'Subscript' object has no attribute 'name'

I have a recent copy of pylint-protobuf (but it does not have a version), and astroid is >>> pylint_protobuf.astroid.__version__ '2.1.0' running on py3.7.2.

This error does not happen when I run the linter on the file itself, but it does when I run it on the parent module:

pylint --load-plugins pylint_protobuf --exit-zero Transform/RIB_2/src/create_test_geo_protobuf.py - this is fine, but pylint --load-plugins pylint_protobuf --exit-zero Transform/RIB_2/src - this fails.

The Transform/RIB_2/src contains an empty __init__.py.

nelfin commented 5 years ago

Hi @endafarrell, it's pretty hard to recreate this based just on what you've got here but here's my guess:

fixture/
├── __init__.py
├── person_pb2.py
└── src
    ├── something.py  # <- your working create_test_geo_protobuf.py in this example
    ├── __init__.py
    └── something_else.py  # <- the actual module that's causing this exception

When you run pylint --load-plugins pylint_protobuf --exit-zero Transform/RIB_2/src it's tripping up on some other file that looks like it might contain a construct like this:

from ..person_pb2 import Person
types = {
    'my_person': Person,
}
p = types['my_person']()

I can recreate the traceback you posted with this construct, and a similar behaviour to what you described with this directory layout, so I'll work on fixing this case. However, can you help me out by checking which of the actual files in your Transform/RIB_2/src is causing this, just so I'm not missing some other case? Something like this ought to do it:

for $f in Transform/RIB_2/src/*; do
  pylint --load-plugins pylint_protobuf --exit-zero $f
done
endafarrell commented 5 years ago

Hi @nelfin - thanks for looking into this.

When run on a loop over each file in Transform/RIB_2/src/* there are no errors - the error happens only when I ask it run over the directory Transform/RIB_2/src. with the --load-plugins pylint_protobuf. Running this completed ok without the AttributeError: 'Subscript' object has no attribute 'name' error:

for f in Transform/RIB_2/src/*
do
    pylint --load-plugins pylint_protobuf --errors-only ${f}
done

As we saw earlier, the error was when a "core" pylint method called the plugin:

  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/utils.py", line 1266, in walk
    cb(astroid)
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint_protobuf/__init__.py", line 142, in visit_call
    name = func.name
AttributeError: 'Subscript' object has no attribute 'name'

I ran pip install loguru and hacked the __init__.py to see what the variables in the stack were by adding from loguru import logger in the imports, and decorating the visit_call method with @logger.catch(reraise=True). Rerunning now gives a lot of extra details but deep in the middle of the outout I could find this ...

    │    │    └ <ClassDef.GeometryOGR l.189 at 0x10e4e9128>
    │    └ <bound method PyLintASTWalker.walk of <pylint.utils.PyLintASTWalker object at 0x10e261ef0>>
    └ <pylint.utils.PyLintASTWalker object at 0x10e261ef0>
  File "/Users/efarrell/anaconda/envs/LG-py37/lib/python3.7/site-packages/pylint/utils.py", line 1269, in walk
    self.walk(child)
    │    │    └ <FunctionDef.create_geometry l.362 at 0x10e5110b8>

Our class.function GeometryOGR.create_geometry uses the OGR library from GDAL (https://anaconda.org/conda-forge/gdal). Before conda made it available, it was difficult to build/install, so I think it has some not-usual magic in its' internals.

By marking that method # pylint: disable-all I am able to run pylint --load-plugins pylint_protobuf Transform/RIB_2 without that error.

Normally, I'd suggest that we could close this as being a rare incompatibility, but you'd probably want to note this somewhere in the docs.

nelfin commented 5 years ago

Hi @endafarrell, I've pushed up a pre-release version that fixes this particular issue: eliminating the AttributeError on forms outside my original expectations. That should prevent any exceptions being thrown when checking modules like in your case (without the need for annotations like # pylint: disable-all). You should be able to benefit from these fixes immediately by installing the latest pre-release with pip install 'pylint_protobuf==0.2.dev2' (or conda install 'pylint_protobuf==0.2.dev2' as the case may be), but I have a partially working patch for inferring the type and I'll ping you when that releases.