Skip to content

Conversation

@fmigneault
Copy link
Contributor

Steps

  • For new features or bug fixes, add a ChangeLog entry describing what your PR does.
  • Write a good description on what the PR does.

Description

Fixes issue #713 by providing corresponding transform and unit tests.

Type of Changes

Type
🐛 Bug fix
✨ New feature

Related Issue

Closes #713

@fmigneault fmigneault changed the title add support to 'six.with_metaclass' add support of 'six.with_metaclass' Sep 12, 2020
@fmigneault
Copy link
Contributor Author

fmigneault commented Sep 12, 2020

flagged pylint issues are related to very recent merge of pylint-dev/pylint#3782 with fix of issue pylint-dev/pylint#3468

@tkukushkin
Copy link

@fmigneault please pay attention to #713 (comment). This code

from enum import Enum, EnumMeta import six class FooMeta(EnumMeta): pass class Foo(six.with_metaclass(FooMeta, Enum)): bar = 1

produces error with this fix:

foo.py:3: [W0611 unused-import] Unused import six 
@fmigneault
Copy link
Contributor Author

@tkukushkin
I don't know enough the internals of astroid to address that specific issue of #841 (comment). Maybe @PCManticore (or other dev from astroid) can help?

The problem in is that after six.with_metaclass(FooMeta, Enum) is processed, the ClassDef effectively becomes:

ClassDef.FooMeta(name='FooMeta', doc=None, decorators=None, bases=[<Name.EnumMeta l.6 at 0x7ff0d24e1a10>], body=[<Pass l.7 at 0x7ff0d24e1a90>]) 

Therefore there is no more reference to six as seen in the source code. At runtime, the class definition is "converted" and doesn't need six anymore. Is there some way to maintain that reference somewhere in the ClassDef for the check to find it?

@tkukushkin
Copy link

@fmigneault I completely understand the cause of this problem and I don't know not hacky solutions and PCManticore did not respond to my comment. That's why I didn't make pull request with this transform.

Copy link
Contributor

@PCManticore PCManticore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall the change looks good, but we need to drop the inference check from the predicate function as it can result in weird inference bugs.

if not isinstance(base, nodes.Call):
return False
try:
func = next(base.func.infer())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we cannot use inference in predicate functions. Here you would need o unpack the arguments for checking if they refer to six.with_metaclass or not (by unpacking I mean either checking explicitly for Name or Attribute instances that match against six.with_metaclass)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be good now. Let me know if it is still not what like you meant.

@PCManticore PCManticore merged commit 4629b93 into pylint-dev:master Feb 7, 2021
@PCManticore
Copy link
Contributor

Thanks for the PR @fmigneault !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

3 participants