11

I'm trying to use the FieldMixin from this answer in my project, but I'm having trouble getting it to pass mypy checks. The current code:

class DynamicFieldsMixin(Serializer):
    context: Dict[str, Any]

    def get_field_names(
        self, declared_fields: OrderedDict, info: FieldInfo
    ) -> Set[str]:
        field_names: Set[str] = self.context.get(
            "fields",
            super().get_field_names(declared_fields, info)
        )
        return field_names

Inheriting from rest_framework.serializers.Serializer seems weird, and I wonder if there's a way to avoid that, since it's meant to be mixed into actual Serializer classes. Just removing the superclass results in this error:

error: "get_field_names" undefined in superclass

mypy configuration:

[mypy]
check_untyped_defs = true
disallow_untyped_defs = true
ignore_missing_imports = true
no_implicit_optional = true
warn_redundant_casts = true
warn_return_any = true
warn_unused_ignores = true
l0b0
  • 55,365
  • 30
  • 138
  • 223
  • Seems like `mypy` should just ignore `super`, since the interface of its return value is inherently determined at runtime, not statically. – chepner Jul 11 '19 at 14:37

1 Answers1

8

You can introduce the base class for the sake of type checking only:

import typing
from typing import Any, Dict, List, Mapping, TypeVar
from rest_framework.fields import Field
from rest_framework.serializers import ModelSerializer
from rest_framework.utils.model_meta import FieldInfo


if typing.TYPE_CHECKING:
    _Base = ModelSerializer
else:
    _Base = object


class DynamicFieldsMixin(_Base):
    context: Dict[str, Any]

    def get_field_names(self, declared_fields: Mapping[str, Field], info: FieldInfo) -> List[str]:
        field_names = super().get_field_names(declared_fields, info)
        # Revealed type is 'builtins.list[builtins.str]'
        reveal_type(field_names)
        return field_names
hoefling
  • 59,418
  • 12
  • 147
  • 194
  • 3
    This causes "error: Invalid base class" when validating. – l0b0 Jul 11 '19 at 21:44
  • Interestingly I get the same error if I simply pull out the parent class name as a variable, with no conditional! – l0b0 Jul 11 '19 at 21:57
  • 1
    I've [reported](https://github.com/python/mypy/issues/2477#issuecomment-510676044) the failure; let's see if there's a solution in place. – l0b0 Jul 11 '19 at 22:46
  • I can't reproduce this issue. `pip install mypy djangorestframework-stubs` in a new venv, validation of the code from the answer with your config or just `--strict` succeeds with `mypy==0.701` and `mypy==0.711`. I guess the error you get has more puzzle pieces, maybe context-specific? If your project is public, can you share the link to its source code? – hoefling Jul 12 '19 at 11:06
  • BTW tested with Python 3.6.8 on Linux if that matters. – hoefling Jul 12 '19 at 11:09