Type hinting for `load` is too strict
The type hinting for load's data argument is set to typing.Mapping which makes sense for the many=False case, but for many=True case the type of data is list, which isn't a Mapping type.
That sounds like an opportunity for @overload and Literal[True]. https://mypy.readthedocs.io/en/latest/literal_types.html
Ah, right, the typing isn't completely correct. PRs welcome!
https://github.com/marshmallow-code/marshmallow/pull/1488 fixes this.
The fix isn't quite right. The merged code returns a Union[T, List[T]], but that means my calling code has to handle both cases, even though I'm either calling it with many=True or many=False, not both. Instead, the return type should be dependent on the value of the many parameter.
I believe the way to make the signatures depend on the values of the parameters is
@overload
def f(data: T1, many: Literal[False]) -> T2: ...
@overload
def f(data: Iterable[T1], many: Literal[True]) -> List[T2]: ...
Is there a way to make it work when many=None, i.e. when self.many is used?
Depending on pre_load decorators, the input with many=True could even be a non-iterable. E.g. list nested in a {'data': my_list} envelope.
Is there a way to make it work when many=None, i.e. when self.many is used?
That might require a mypy plugin, I'm not sure. Some of the experts answer questions in https://gitter.im/python/typing, I've gotten help there before.
It makes me wonder whether schemas with self.many=True should instead be regular schemas wrapped up like Many(MySchema()).
@jtrakk Would you like to investigate this further and send a PR to improve the typing? I'm afraid I won't be able to look into this within the next few weeks (lots of work and non-work commitments this month).
It makes me wonder whether schemas with self.many=True should instead be regular schemas wrapped up like Many(MySchema()).
Or even List(MySchema()). But then it'd be difficult to encapsulate all the pre-/post- processing stuff in a single class, e.g. I'm not sure how you'd express this example.
Anyway, that's a larger change we could consider in the future. For now, let's improve the typing with the current API.
I'm afraid I won't be able to look into this within the next few weeks
I'm in the same boat there; Sorry to dump these suggestions on you and run away :-)
The same issue is with dump method with many=True
It seems that, assuming pure Python typing, this could almost be expressed using generic types with default values (akin to Rust associated types).
The problem is self.many, since it silently changes the input and return types without actually changing call signatures 😔 Because of that, I think a plugin is the only way to do it without changing the API.