PY-27656 PY-27604 Exclude ancestors of metaclasses from class hierarchy

in case this relationship was created implicitly by inheriting an
instance of metaclass.

It also fixes warnings about the first parameter of SQLAlchemy model
methods being named "self" instead of "cls" since we no longer consider
these classes descendants of "type".
This commit is contained in:
Mikhail Golubev
2018-01-11 12:45:08 +03:00
parent 8ab8f2994f
commit f7da96db03
3 changed files with 34 additions and 1 deletions
@@ -427,7 +427,22 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
final List<List<PyClassLikeType>> lines = new ArrayList<>();
for (PyClassLikeType base : bases) {
if (base != null) {
final List<PyClassLikeType> baseClassMRO = mroLinearize(base, true, context, cache);
// Don't include ancestors of a metaclass instance
final List<PyClassLikeType> baseClassMRO;
if (base.isDefinition()) {
baseClassMRO = mroLinearize(base, true, context, cache);
}
else {
List<PyClassLikeType> metaclassInstanceMro = new ArrayList<>();
metaclassInstanceMro.add(base);
if (base instanceof PyClassType) {
final PyClassImpl pyClass = as(((PyClassType)base).getPyClass(), PyClassImpl.class);
if (pyClass != null) {
ContainerUtil.addIfNotNull(metaclassInstanceMro, pyClass.getImplicitSuper(context));
}
}
baseClassMRO = metaclassInstanceMro;
}
if (!baseClassMRO.isEmpty()) {
// mroMerge() updates passed MRO lists internally
lines.add(new LinkedList<>(baseClassMRO));
@@ -0,0 +1,13 @@
class MetaBase(type):
pass
class Meta(MetaBase):
pass
Base = Meta('Base', (), {})
class MyClass(Base):
pass
@@ -125,6 +125,11 @@ public class PyClassMROTest extends PyTestCase {
assertMRO(getClass("MyClass"), "Base", "object");
}
// PY-27656
public void testDirectlyInstantiatedMetaclassAncestor() {
runWithLanguageLevel(LanguageLevel.PYTHON30, () -> assertMRO(getClass("MyClass"), "Meta", "object"));
}
// PY-20026
public void testUnresolvedMetaClassAncestors() {
runWithLanguageLevel(LanguageLevel.PYTHON30, () -> assertMRO(getClass("CompositeFieldMeta"), "type", "object"));