Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash 'AssignAttr' object has no attribute 'qname' #5717

Closed
iloveagent57 opened this issue Jan 24, 2022 · 11 comments
Closed

Crash 'AssignAttr' object has no attribute 'qname' #5717

iloveagent57 opened this issue Jan 24, 2022 · 11 comments
Assignees
Labels
Astroid Related to astroid Crash 💥 A bug that makes pylint crash
Milestone

Comments

@iloveagent57
Copy link

iloveagent57 commented Jan 24, 2022

Bug description

I've seen this bug at various times over the past year or so, but I can't deterministically re-produce it. The failure this time was when linting the file: https://github.com/openedx/license-manager/blob/aed/fix-lint/license_manager/apps/api/tests/test_tasks.py

Configuration

https://github.com/openedx/license-manager/blob/aed/fix-lint/pylintrc

Command used

pylint --rcfile=pylintrc license_manager/apps/api/tests/test_tasks.py

Pylint output

Exception on node <Call l.761 at 0x7fa478f2b9d0> in file '/edx/app/license_manager/license_manager/apps/api/tests/test_tasks.py'
Traceback (most recent call last):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/pylint/utils/ast_walker.py", line 72, in walk
    callback(astroid)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/pylint/checkers/base.py", line 789, in visit_call
    self._check_inferred_class_is_abstract(inferred, node)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/pylint/checkers/base.py", line 804, in _check_inferred_class_is_abstract
    abstract_methods = _has_abstract_methods(inferred)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/pylint/checkers/base.py", line 395, in _has_abstract_methods
    return len(utils.unimplemented_abstract_methods(node)) > 0
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/pylint/checkers/utils.py", line 934, in unimplemented_abstract_methods
    inferred = safe_infer(obj)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/pylint/checkers/utils.py", line 1251, in safe_infer
    value = next(infer_gen)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/node_ng.py", line 150, in infer
    yield from self._infer(context, **kwargs)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 142, in raise_if_nothing_inferred
    yield next(generator)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 111, in wrapped
    for res in _func(node, context, **kwargs):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/bases.py", line 157, in _infer_stmts
    for inf in stmt.infer(context=context):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/node_ng.py", line 164, in infer
    for i, result in enumerate(generator):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 142, in raise_if_nothing_inferred
    yield next(generator)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 111, in wrapped
    for res in _func(node, context, **kwargs):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/inference.py", line 241, in infer_call
    for callee in self.func.infer(context):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/node_ng.py", line 164, in infer
    for i, result in enumerate(generator):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 142, in raise_if_nothing_inferred
    yield next(generator)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 111, in wrapped
    for res in _func(node, context, **kwargs):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/bases.py", line 157, in _infer_stmts
    for inf in stmt.infer(context=context):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/node_ng.py", line 164, in infer
    for i, result in enumerate(generator):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 142, in raise_if_nothing_inferred
    yield next(generator)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 111, in wrapped
    for res in _func(node, context, **kwargs):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/inference.py", line 293, in infer_import_from
    module = self.do_import_module()
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/mixins.py", line 108, in do_import_module
    return mymodule.import_module(
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py", line 739, in import_module
    return AstroidManager().ast_from_module_name(absmodname)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/manager.py", line 211, in ast_from_module_name
    return self.ast_from_file(found_spec.location, modname, fallback=False)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/manager.py", line 124, in ast_from_file
    return AstroidBuilder(self).file_build(filepath, modname)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/builder.py", line 151, in file_build
    return self._post_build(module, encoding)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/builder.py", line 171, in _post_build
    self.delayed_assattr(delayed)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/builder.py", line 241, in delayed_assattr
    for inferred in node.expr.infer():
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/node_ng.py", line 150, in infer
    yield from self._infer(context, **kwargs)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 142, in raise_if_nothing_inferred
    yield next(generator)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 111, in wrapped
    for res in _func(node, context, **kwargs):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/bases.py", line 157, in _infer_stmts
    for inf in stmt.infer(context=context):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/node_ng.py", line 164, in infer
    for i, result in enumerate(generator):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 142, in raise_if_nothing_inferred
    yield next(generator)
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/decorators.py", line 111, in wrapped
    for res in _func(node, context, **kwargs):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/inference.py", line 956, in infer_assign
    stmts = list(self.assigned_stmts(context=context))
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/protocols.py", line 357, in _arguments_infer_argname
    is_metaclass = isinstance(cls, nodes.ClassDef) and cls.type == "metaclass"
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2095, in _class_type
    if _is_metaclass(klass):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2081, in _is_metaclass
    if _is_metaclass(baseobj, seen):
  File "/edx/app/license-manager/venvs/license-manager/lib/python3.8/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2065, in _is_metaclass
    baseobj_name = baseobj.qname()
AttributeError: 'AssignAttr' object has no attribute 'qname'

Expected behavior

That there is no AssignAttr exception

Pylint version

pylint 2.12.2
astroid 2.9.3
Python 3.8.10 (default, May  5 2021, 03:01:07)
[GCC 7.5.0]

OS / Environment

Running in a Docker container based on ubuntu:bionic

No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.5 LTS
Release: 18.04
Codename: bionic

Additional dependencies

amqp==2.6.1
analytics-python==1.4.0
asgiref==3.4.1
astroid==2.9.3
attrs==21.4.0
backoff==1.10.0
billiard==3.6.4.0
boto3==1.20.37
botocore==1.23.37
celery==4.4.7
certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.10
click==7.1.2
click-log==0.3.2
code-annotations==1.2.0
confluent-kafka==1.8.2
coreapi==2.3.3
coreschema==0.0.4
coverage==6.2
cryptography==36.0.1
ddt==1.4.4
defusedxml==0.7.1
diff-cover==4.0.0
Django==3.2.11
django-cors-headers==3.11.0
django-crum==0.7.9
django-debug-toolbar==3.2.4
django-durationwidget==1.0.5
django-dynamic-fixture==3.1.2
django-extensions==3.1.5
django-filter==21.1
django-model-utils==4.2.0
django-ses==2.3.1
django-simple-history==3.0.0
django-waffle==2.3.0
djangorestframework==3.13.1
djangorestframework-csv==2.1.1
drf-jwt==1.19.2
drf-nested-routers==0.93.4
drf-yasg==1.20.0
edx-api-doc-tools==1.5.0
edx-auth-backends==4.0.1
edx-braze-client==0.1.0
edx-celeryutils==1.1.1
edx-django-utils==4.4.1
edx-drf-extensions==8.0.1
edx-i18n-tools==0.8.1
edx-lint==5.2.1
edx-opaque-keys==2.2.2
edx-rbac==1.5.1
edx-rest-api-client==5.4.1
edx-toggles==4.2.0
factory-boy==3.2.1
Faker==11.3.0
fastavro==1.4.9
freezegun==1.1.0
future==0.18.2
gunicorn==20.1.0
idna==3.3
inflect==5.3.0
inflection==0.5.1
iniconfig==1.1.1
isort==5.10.1
itypes==1.2.0
Jinja2==3.0.3
jinja2-pluralize==0.3.0
jmespath==0.10.0
jsonfield==3.1.0
kombu==4.6.11
lazy-object-proxy==1.7.1
MarkupSafe==2.0.1
mccabe==0.6.1
monotonic==1.6
mysqlclient==2.1.0
newrelic==7.2.4.171
oauthlib==3.1.1
packaging==21.3
path==16.3.0
pathlib2==2.3.6
pbr==5.8.0
pep517==0.12.0
pip-tools==6.4.0
platformdirs==2.4.1
pluggy==1.0.0
polib==1.1.1
psutil==5.9.0
py==1.11.0
pycodestyle==2.8.0
pycparser==2.21
pycryptodomex==3.12.0
pydocstyle==6.1.1
Pygments==2.11.2
pyjwkest==1.4.2
PyJWT==2.3.0
pylint==2.12.2
pylint-celery==0.3
pylint-django==2.5.0
pylint-plugin-utils==0.7
pymongo==4.0.1
pyparsing==3.0.6
pytest==6.2.5
pytest-cov==3.0.0
pytest-django==4.5.2
python-dateutil==2.8.2
python-slugify==5.0.2
python3-openid==3.2.0
pytz==2021.3
pywatchman==1.4.1
PyYAML==6.0
redis==3.5.3
requests==2.27.1
requests-oauthlib==1.3.0
ruamel.yaml==0.17.20
ruamel.yaml.clib==0.2.6
rules==3.1
s3transfer==0.5.0
semantic-version==2.8.5
simplejson==3.17.6
six==1.16.0
slumber==0.7.1
snowballstemmer==2.2.0
social-auth-app-django==5.0.0
social-auth-core==4.2.0
sqlparse==0.4.2
stevedore==3.5.0
text-unidecode==1.3
toml==0.10.2
tomli==2.0.0
typing_extensions==4.0.1
unicodecsv==0.14.1
uritemplate==4.1.1
urllib3==1.26.8
vine==1.3.0
wrapt==1.11.2
zipp==3.7.0

@iloveagent57 iloveagent57 added the Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling label Jan 24, 2022
@DanielNoord DanielNoord added Crash 💥 A bug that makes pylint crash and removed Needs triage 📥 Just created, needs acknowledgment, triage, and proper labelling labels Jan 24, 2022
@Pierre-Sassoulas Pierre-Sassoulas added this to the 2.13.0 milestone Jan 24, 2022
@areveny
Copy link
Contributor

areveny commented Jan 25, 2022

I can reproduce the crash consistently after installing the dependencies with the Makefile in openedx/license-manager https://github.com/openedx/license-manager.

This is the call being visited that causes this crash: https://github.com/openedx/license-manager/blob/master/license_manager/apps/api/tests/test_tasks.py

    @mock.patch('license_manager.apps.api.tasks.EnterpriseApiClient', return_value=mock.MagicMock())
    @mock.patch('license_manager.apps.api.tasks.BrazeApiClient', return_value=mock.MagicMock())
    def test_email_already_sent(self, mock_braze_api_client, mock_enterprise_api_client):
        """
        Tests that email is not sent if it's already been sent before.
        """
        notification = Notification(
            enterprise_customer_uuid=self.subscription_plan.enterprise_customer_uuid,
            enterprise_customer_user_uuid=self.test_ecu_id,
            subscripton_plan_id=self.subscription_plan.uuid,
            notification_type=NotificationChoices.PERIODIC_INFORMATIONAL
        )
        notification.save()

The specific call being visited is Notification(...

The problem node comes from the freezegun module: https://github.com/spulec/freezegun/blob/master/freezegun/api.py

        # Change the modules
        datetime.datetime = FakeDatetime
        datetime.date = FakeDate

The attribute with no qname is datetime.datetime. This is a good lead on a minimal reproducing example.

This gets inferred in the context of django-model-utils/fields.py (https://github.com/jazzband/django-model-utils/blob/master/model_utils/fields.py) which might complicate things if it's only the interaction of django and freezegun. I can't get the error from just running Pylint on freezegun.api.

I don't have the availability to self-assign but if nobody else is taking this on I'll keep plugging away at it. It will probably become an Astroid issue down the road.

@areveny areveny changed the title Crash 'AssignAttr' object has no attribute 'qname' (if possible, be more specific about what made pylint crash) Crash 'AssignAttr' object has no attribute 'qname' Jan 25, 2022
@iloveagent57
Copy link
Author

Thank you so much for picking this up, I'm glad you were able to reproduce the issue!

@DanielNoord DanielNoord added the Downstream Bug 🪲 The problem happens in a lib depending on pylint, not pylint label Jan 28, 2022
@DanielNoord
Copy link
Collaborator

DanielNoord commented Jan 28, 2022

Adding downstream bug as my investigation here pylint-dev/astroid#1373 (comment) shows that this is likely a bug in pylint-django rather than in pylint or astroid.

Off topic:
@Pierre-Sassoulas This would probably be quite difficult and just something to keep in mind for the future (don't think we should open an issue), but it would be really neat if the issue template showed when something is a downstream bug and where to report it then. We can dream... 😄

@Pierre-Sassoulas
Copy link
Member

the issue template showed when something is a downstream bug

We could advertise the existence of pylint-django and prospector which are two major libs building on top of pylint. (Although it's impossible to automate the label creation, it's set once)

@DanielNoord
Copy link
Collaborator

the issue template showed when something is a downstream bug

We could advertise the existence of pylint-django and prospector which are two major libs building on top of pylint. (Although it's impossible to automate the label creation, it's set once)

I meant the issue template which is given to users when pylint crashes 😉 Perhaps we could explore using a regex on the last line of the stacktrace and seeing if it includes pylint_django? There are more pressing matters though.

@areveny areveny added Astroid Related to astroid and removed Downstream Bug 🪲 The problem happens in a lib depending on pylint, not pylint labels Jan 28, 2022
@areveny
Copy link
Contributor

areveny commented Feb 23, 2022

This PR attempts to fix a root cause of all these issues got merged recently: pylint-dev/pylint-django#350

I'll test shortly if this change closes these issues--I have a bit of confusion around when pylint-django gets used so I want to make sure. If I can get it going, upgrading pylint-django to 2.5.2 would fix this crash.

@areveny
Copy link
Contributor

areveny commented Feb 23, 2022

Hey @iloveagent57,

Try upgrading your version of pylint-django to 2.5.2 from 2.5.0. Switching between the two on my skeleton installation of license-manager is surfacing/preventing the crash. A backend change resulting from this investigation should do the trick.

I'll close this issue in a few days unless there issue keeps resurfacing on your end.

@areveny
Copy link
Contributor

areveny commented Feb 27, 2022

Resolved by the merged pylint-django issue: pylint-dev/pylint-django#349

Please open a new issue if this reemerges after upgrading pylint-django to 2.5.2.

@areveny areveny closed this as completed Feb 27, 2022
@DanielNoord
Copy link
Collaborator

@areveny Sorry, I was messing up issues and reports. The comment I referred to in pylint-dev/astroid#1374 (comment) was indeed fixed.

However, has the above actually been fixed? This is a astroid stacktrace not one from pylint-django. Django also doesn't feature once in the stacktrace.

@areveny
Copy link
Contributor

areveny commented Feb 27, 2022

Ah! I'm actually even more confident about this one.

pylint-django is accessed many times during inference of the original reporter's test file, confirmed by inserting a print statement. The errant AssignAttr node is returned by a pylint-django transform and doesn't get qname accessed in pylint until later, producing the above stack trace.

Furthermore I have been able to reproduce here (turns out I didn't delete my environment yet) and I can comment the new code in and out to reintroduce/fix the crash above.

@DanielNoord
Copy link
Collaborator

Perfect! Thanks for looking into this :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Astroid Related to astroid Crash 💥 A bug that makes pylint crash
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants