Skip to content

Cannot determine type of attribute class in base class #4956

Closed

Description

@OJFord
class Foo:
    class Thing(object): # type: ignore
        pass

class Thing:
    pass

class Bar:
    Thing = Thing

class FooBar(Foo, Bar):
    pass

scratch.py:11: error: Cannot determine type of 'Thing' in base class 'Foo'

Adding object doesn't help, nor #type: ignore as shown above.

However, Bar.Thing does type check; so there seems only to be a problem typing literal class-valued class attributes, when inherited. (Aside: many thanks if you can tell me the proper terminology for these Bar.Thing and Foo.Things - it's not easy to search for!)

Note Foo.Thing is not a problem until the inheriting class is introduced on L11.

Activity

  1. ilevkivskyi commented on Apr 24, 2018

    @ilevkivskyi
    Member

    This is not a bug but how mypy works. The error message can be made clearer however. The point is that inner classes are treated as types, not variables (i.e. as statically known), they cannot be re-assigned, but can be used in type annotations. On the contrary, an instance variable with type Type[Thing] (this is what is created by the assignment in your example) can be re-assigned, but can't be used in type annotations.

  2. OJFord commented on Apr 24, 2018

    @OJFord
    Author

    @ilevkivskyi Many thanks for your reply. I think it might help to explain why this is causing me a problem.

    My Foo and Bar are really Django model 'mixins' (in quotes because they must inherit from Django's Model in order to provide extra ORM fields) and the inner class Thing is really Django's Meta, (not an actual metaclass) necessary to specify Meta.abstract = True in order not to create extra database tables for the 'mixin' itself.

    The problem then is that, with Meta as inner class, mypy cannot determine its type; with Meta as instance variable, it conflicts with multiple 'mixins' (inheritance):

    class IdMeta:
        abstract = True
        ordering = ('id,')
    
    class Id(Model):
        Meta = IdMeta
        id = IntegerField(...)
    
    class CreatedMeta:
        abstract = True
    
    class Created(Model):
        Meta = CreatedMeta
        created = DateTimeField(...)
    
    class RealModel(Model, Id, Created):
        ...

    error: Definition of "Meta" in base class "Created" is incompatible with definition in base class "Id"

  3. ilevkivskyi commented on Apr 24, 2018

    @ilevkivskyi
    Member

    Support of Django is a separate project and will require writing a plugin, see #3539 (there are too much magic to typecheck normally).

    Also it looks like we already have a very similar issue to yours #3855 with a similar motivation. So I think we can close this, feel free to re-open if you think this is a separate issue.

  4. OJFord commented on Apr 24, 2018

    @OJFord
    Author

    Thanks; apologies - it's certainly a duplicate.

    Is there any way to workaround this though? At this point I would be quite happy with # type: ignore, or similar, but that doesn't work. Or is it simply not possible to use mypy in a Django project with this pattern?

  5. ilevkivskyi commented on Apr 24, 2018

    @ilevkivskyi
    Member

    I think # type: ignore at the point of use (i.e. at line 11 in your example) should work.

  6. OJFord commented on Apr 24, 2018

    @OJFord
    Author

    Nope, it complains before then, i.e. my RealModel is in a different file, but running mypy on just the file with the 'mixins' fails with:

    error: Cannot determine type of 'Meta' in base class 'Foo'

    # type: ignore on the Meta inner class has no impact; nor does putting it on the outer 'mixin' model Foo.

  7. ilevkivskyi commented on Apr 24, 2018

    @ilevkivskyi
    Member

    Can you put # type: ignore on the line where it is reported? (This is how ignores are supposed to work, they just silence errors.)

  8. OJFord commented on Apr 24, 2018

    @OJFord
    Author

    Oh no - sorry - I'm not sure how I screwed that up, that does work. Many thanks!

  9. syenchuk commented on Nov 8, 2018

    @syenchuk

    FYI, similar issues #2871 #3855

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions