Repository: samuelcolvin/pydantic
Pull request #4211 (2022-07-04 21:47:02)

Bump mypy to 0.971
<!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
<!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->

## Change Summary
Bump mypy to 0.961

Here is the error that I ignored:
```
pydantic/mypy.py:104: error: Incompatible return value type (got "Callable[[ClassDefContext], bool]", expected "Optional[Callable[[ClassDefContext], None]]")  [return-value]
Found 1 error in 1 file (checked 26 source files)
```
It seems mypy introduced the change in return type of `get_class_decorator_hook` in https://github.com/python/mypy/commit/03901ef657daf6f477e6fe933c42ac270cf5034b
<!-- Please give a short summary of the changes. -->

## Related issue number

<!-- Are there any issues opened that will be resolved by merging this change? -->
<!-- WARNING: please use "fix #123" style references so the issue is closed when this PR is merged. -->

## Checklist

* [ ] Unit tests for the changes exist
* [x] Tests pass on CI and coverage remains at 100%
* [ ] Documentation reflects the changes where applicable
* [ ] `changes/<pull request or issue id>-<github username>.md` file added describing change
  (see [changes/README.md](https://github.com/samuelcolvin/pydantic/blob/master/changes/README.md) for details)
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


hramezani: please review
hramezani: @samuelcolvin Could you please take a look at this PR?

Patch:
diff --git a/changes/4253-sergeytsaplin.md b/changes/4253-sergeytsaplin.md
new file mode 100644
index 000000000..6cdee03ca
--- /dev/null
+++ b/changes/4253-sergeytsaplin.md
@@ -0,0 +1,1 @@
+Allow empty string aliases by using a `alias is not None` check, rather than `bool(alias)`
diff --git a/docs/usage/exporting_models.md b/docs/usage/exporting_models.md
index 1673c45d5..62aca5b02 100644
--- a/docs/usage/exporting_models.md
+++ b/docs/usage/exporting_models.md
@@ -97,7 +97,7 @@ the values should be functions which serialise that type (see the example below)
 _(This script is complete, it should run "as is")_
 
 By default, `timedelta` is encoded as a simple float of total seconds. The `timedelta_isoformat` is provided
-as an optional alternative which implements ISO 8601 time diff encoding.
+as an optional alternative which implements [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) time diff encoding.
 
 The `json_encoders` are also merged during the models inheritance with the child
 encoders taking precedence over the parent one.
diff --git a/docs/usage/types.md b/docs/usage/types.md
index 0651bead5..02e9c43de 100644
--- a/docs/usage/types.md
+++ b/docs/usage/types.md
@@ -360,7 +360,7 @@ types:
   * `str`, following formats work:
 
     * `[-][DD ][HH:MM]SS[.ffffff]`
-    * `[±]P[DD]DT[HH]H[MM]M[SS]S` (ISO 8601 format for timedelta)
+    * `[±]P[DD]DT[HH]H[MM]M[SS]S` ([ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format for timedelta)
 
 ```py
 {!.tmp_examples/types_dt.py!}
diff --git a/pydantic/fields.py b/pydantic/fields.py
index 600ee5364..7b55bcf63 100644
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -148,7 +148,7 @@ class FieldInfo(Representation):
         self.default = default
         self.default_factory = kwargs.pop('default_factory', None)
         self.alias = kwargs.pop('alias', None)
-        self.alias_priority = kwargs.pop('alias_priority', 2 if self.alias else None)
+        self.alias_priority = kwargs.pop('alias_priority', 2 if self.alias is not None else None)
         self.title = kwargs.pop('title', None)
         self.description = kwargs.pop('description', None)
         self.exclude = kwargs.pop('exclude', None)
@@ -394,8 +394,8 @@ class ModelField(Representation):
     ) -> None:
 
         self.name: str = name
-        self.has_alias: bool = bool(alias)
-        self.alias: str = alias or name
+        self.has_alias: bool = alias is not None
+        self.alias: str = alias if alias is not None else name
         self.type_: Any = convert_generics(type_)
         self.outer_type_: Any = type_
         self.class_validators = class_validators or {}
diff --git a/pydantic/mypy.py b/pydantic/mypy.py
index 8229b726f..f8434900e 100644
--- a/pydantic/mypy.py
+++ b/pydantic/mypy.py
@@ -101,7 +101,7 @@ class PydanticPlugin(Plugin):
 
     def get_class_decorator_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
         if fullname == DATACLASS_FULLNAME:
-            return dataclasses.dataclass_class_maker_callback
+            return dataclasses.dataclass_class_maker_callback  # type: ignore[return-value]
         return None
 
     def _pydantic_model_class_maker_callback(self, ctx: ClassDefContext) -> None:


Test patch:
diff --git a/tests/requirements-linting.txt b/tests/requirements-linting.txt
index 50de9c43c..bd1f3e843 100644
--- a/tests/requirements-linting.txt
+++ b/tests/requirements-linting.txt
@@ -4,7 +4,7 @@ flake8-quotes==3.3.1
 hypothesis==6.53.0
 isort==5.10.1
 pyupgrade==2.37.3
-mypy==0.950
+mypy==0.971
 pre-commit==2.20.0
 pycodestyle==2.9.0
 pyflakes==2.5.0
diff --git a/tests/requirements-testing.txt b/tests/requirements-testing.txt
index 0f8ac5d6f..c86acd2de 100644
--- a/tests/requirements-testing.txt
+++ b/tests/requirements-testing.txt
@@ -2,7 +2,7 @@ coverage==6.4.2
 hypothesis==6.53.0
 # pin importlib-metadata as upper versions need typing-extensions to work if on Python < 3.8
 importlib-metadata==3.1.0;python_version<"3.8"
-mypy==0.950
+mypy==0.971
 pytest==7.1.2
 pytest-cov==3.0.0
 pytest-mock==3.8.2
diff --git a/tests/test_aliases.py b/tests/test_aliases.py
index 24caa9ed6..53a08dc0a 100644
--- a/tests/test_aliases.py
+++ b/tests/test_aliases.py
@@ -335,3 +335,13 @@ def test_alias_priority():
         'd_config_parent',
         'e_generator_child',
     ]
+
+
+def test_empty_string_alias():
+    class Model(BaseModel):
+        empty_string_key: int = Field(alias='')
+
+    data = {'': 123}
+    m = Model(**data)
+    assert m.empty_string_key == 123
+    assert m.dict(by_alias=True) == data
diff --git a/tests/test_fastapi.sh b/tests/test_fastapi.sh
index ff5a3e3ad..26fcc2174 100755
--- a/tests/test_fastapi.sh
+++ b/tests/test_fastapi.sh
@@ -9,7 +9,6 @@ latest_tag_commit=$(git rev-list --tags --max-count=1)
 latest_tag=$(git describe --tags "${latest_tag_commit}")
 git checkout "${latest_tag}"
 
-pip install -U flit
-flit install
+pip install .[all,dev,doc,test]
 
 ./scripts/test.sh