15

I have something similar to this:

from typing import Type


class Foo:
    pass


def make_a_foobar_class(foo_class: Type[Foo]) -> Type[Foo]:

    class FooBar(foo_class):
        # this.py:10: error: Variable "foo_class" is not valid as a type
        # this.py:10: error: Invalid base class "foo_class"
        pass

    return FooBar


print(make_a_foobar_class(Foo)())

Running mypy throws these two errors (added as comments ^) at line class FooBar(foo_class):

The code seems to work just fine:

$ python this.py
<__main__.make_a_foobar_class.<locals>.FooBar object at 0x10a422be0>

What am I doing wrong?

frnhr
  • 12,354
  • 9
  • 63
  • 90
  • I don't understand all the details and can't explain it, but this seems related: https://github.com/python/mypy/issues/5865 – mkrieger1 Jan 07 '20 at 19:52

1 Answers1

13

Mypy, and the PEP 484 ecosystem in general, does not support creating classes with dynamic base types.

This is likely because supporting such a feature is not worth the additional complexity: the type checker would need to implement additional logic/additional passes since it can no longer cleanly determine what exactly the parent type is by just examining the set of variable names that are currently in scope, and can also no longer accurately type check code using the new dynamic class in the general case.

In any case, I would recommend either redesigning your code to avoid doing this, perhaps by using composition over inheritance or something.

Alternatively, you can suppress the errors mypy is generating by adding a # type: ignore annotation. This annotation will filter out all errors associated with that particular line once type checking is done.

For example:

from typing import Type

class Foo:
    pass

def make_a_foobar_class(foo_class: Type[Foo]) -> Type[Foo]:

    class FooBar(foo_class):  # type: ignore
        pass

    return FooBar

print(make_a_foobar_class(Foo)())
Michael0x2a
  • 58,192
  • 30
  • 175
  • 224