pydantic: Mypy plugin doesn't consider `allow_population_by_field_name`
Initial Checks
- I have searched GitHub for a duplicate issue and I’m sure this is something new
- I have searched Google & StackOverflow for a solution and couldn’t find anything
- I have read and followed the docs and still think this is a bug
- I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)
Description
Probably an issue with the Pydantic mypy plugin. It happened after the mypy 1.0.0 release.
Consider this code, and run mypy --strict
:
from pydantic import BaseModel, Field
class Model(BaseModel):
field: str = Field(alias="alias")
class Config:
allow_population_by_field_name = True
Model(alias="") # OK.
Model(field="") # error: Unexpected keyword argument "field" for "Model" [call-arg]
At runtime, this is fine, because of the allow_population_by_field_name
setting, but the mypy plugin only allows instantiating the class through the alias.
Python, Pydantic & OS Version
Python 3.9.13
Pydantic 1.10.5
Ubuntu on ARM, Linux 5.15.0-58
Affected Components
- Compatibility between releases
- Data validation/parsing
- Data serialization -
.model_dump()
and.model_dump_json()
- JSON Schema
- Dataclasses
- Model Config
- Field Types - adding or changing a particular data type
- Function validation decorator
- Generic Models
- Other Model behaviour -
model_construct()
, pickling, private attributes, ORM mode - Plugins and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 1
- Comments: 26 (22 by maintainers)
@andersfylling, I think what you’re missing is that given the above, only 1 variation can ever be valid at a given time.
Config.allow_population_by_field_name
just switches which one is valid for mypy when used with the plugin.Your first error is for line 10, the second error is for line 9 instead.
For what it’s worth, if this is not resolved by #5111, I would be happy to accept a PR fixing this (in pydantic v1.10.X or v2).
If no one else gets to this first, I expect we will fix this at some point in the not-distant future in connection with the v2 release, but it will definitely happen faster if someone has a chance to figure it out what’s going wrong before then.
For what it’s worth, I would be okay with either of these approaches:
allow_population_by_field_name
isTrue
allow_population_by_field_name
isTrue
I don’t think it’s a good idea to try to support every combination of keyword argument names as that will bog mypy down massively for any model with a large number of keywords, but the all-aliases and no-aliases approach seems reasonable to me.
@andersfylling the issue in the thread was that you get:
In your example, the second case gives the error
error: Missing named argument "field" for "Model"
for the first line, which was addressing the issue presented. (That populate_by_name was being ignored.)Making it produce that is what was necessary to resolve this issue, so what you are asking for is not the issue described in the thread (or at least not in the body of the issue, even if it was discussed above).
I recognize that it may be nice to have it work with either form, but I would consider that a feature request. (And I don’t believe it will be easy to implement.) The problem in this issue (at least as I interpreted it) was that it wasn’t updating the signature to use the field name. That was definitely a bug, and was not the intended behavior. I have never (yet) intended to get both the alias and the field name working in the
__init__
signature, and I worry that would require a lot of effort to implement in the mypy plugin. I would be open to reviewing a PR if someone gets it working though.If you still want the behavior changed, please create a new issue describing the current behavior and what you would like it to do instead.
(You may also be interested in https://github.com/pydantic/pydantic/pull/5433, which (in v2) will provide a way to specify the alias without it affecting the signature used by type checkers, on a per-field basis. This won’t make it so the type checker allows both with and without alias simultaneously, but it may help you get the signature you want without needing the plugin.)
I think it would be a significant improvement to just do two overloads – one that uses all aliases, and one that uses no aliases (when both are acceptable). Usually users are consistent about using one of these two approaches. (I personally would want it to always not use aliases when the field names are acceptable, but I understand not everyone feels the same…)
That said, we’d probably want to make sure that it didn’t result in a significant increase in error message verbosity (and corresponding decrease in clarity) when using invalid keyword arguments, i.e., arguments that aren’t a part of either signature.
I haven’t worked on the mypy plugin for a while (and am not very familiar with pyright) so I don’t know how hard this would be.
Thanks @jonathanslenders for reporting this.
Yes, you are right. I can confirm the problem in
1.10.5
with bothmypy 1.0.1
andmypy 1.1.0+dev
. I’ve tested it onV2
and they returnUnexpected keyword argument "field" for "Model" [call-arg]
with bothmypy 1.0.1
andmypy 1.1.0+dev
@cdce8p I’ve tried your fix on mypy with https://github.com/pydantic/pydantic/pull/5077, but it doesn’t fix the problem on
1.10.x
andV2