Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Update mypy to 0.950 and fix complaints #12650

Merged
merged 16 commits into from
May 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/12650.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update to mypy 0.950.
64 changes: 34 additions & 30 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ flake8-bugbear = "==21.3.2"
flake8 = "*"

# Typechecking
mypy = "==0.931"
mypy-zope = "==0.3.5"
mypy = "*"
mypy-zope = "*"
types-bleach = ">=4.1.0"
types-commonmark = ">=0.9.2"
types-jsonschema = ">=3.2.0"
Expand Down
19 changes: 13 additions & 6 deletions stubs/sortedcontainers/sorteddict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,19 @@ class SortedDict(Dict[_KT, _VT]):
def popitem(self, index: int = ...) -> Tuple[_KT, _VT]: ...
def peekitem(self, index: int = ...) -> Tuple[_KT, _VT]: ...
def setdefault(self, key: _KT, default: Optional[_VT] = ...) -> _VT: ...
@overload
def update(self, __map: Mapping[_KT, _VT], **kwargs: _VT) -> None: ...
@overload
def update(self, __iterable: Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ...
@overload
def update(self, **kwargs: _VT) -> None: ...
# Mypy now reports the first overload as an error, because typeshed widened the type
# of `__map` to its internal `_typeshed.SupportsKeysAndGetItem` type in
# https://github.com/python/typeshed/pull/6653
# Since sorteddicts don't change the signature of `update` from that of `dict`, we
# let the stubs for `update` inherit from the stubs for `dict`. (I suspect we could
# do the same for many othe methods.) We leave the stubs commented to better track
# how this file has evolved from the original stubs.
# @overload
# def update(self, __map: Mapping[_KT, _VT], **kwargs: _VT) -> None: ...
# @overload
# def update(self, __iterable: Iterable[Tuple[_KT, _VT]], **kwargs: _VT) -> None: ...
# @overload
# def update(self, **kwargs: _VT) -> None: ...
def __reduce__(
self,
) -> Tuple[
Expand Down
3 changes: 2 additions & 1 deletion synapse/appservice/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple

from prometheus_client import Counter
from typing_extensions import TypeGuard

from synapse.api.constants import EventTypes, Membership, ThirdPartyEntityKind
from synapse.api.errors import CodeMessageException
Expand Down Expand Up @@ -66,7 +67,7 @@ def _is_valid_3pe_metadata(info: JsonDict) -> bool:
return True


def _is_valid_3pe_result(r: JsonDict, field: str) -> bool:
def _is_valid_3pe_result(r: object, field: str) -> TypeGuard[JsonDict]:
if not isinstance(r, dict):
return False

Expand Down
3 changes: 2 additions & 1 deletion synapse/config/appservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ def load_appservices(
) -> List[ApplicationService]:
"""Returns a list of Application Services from the config files."""
if not isinstance(config_files, list):
logger.warning("Expected %s to be a list of AS config files.", config_files)
# type-ignore: this function gets arbitrary json value; we do use this path.
squahtx marked this conversation as resolved.
Show resolved Hide resolved
logger.warning("Expected %s to be a list of AS config files.", config_files) # type: ignore[unreachable]
return []

# Dicts of value -> filename
Expand Down
4 changes: 3 additions & 1 deletion synapse/events/presence_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ async def get_users_for_states(
# run all the callbacks for get_users_for_states and combine the results
for callback in self._get_users_for_states_callbacks:
try:
result = await callback(state_updates)
# Note: result is an object here, because we don't trust modules to
# return the types they're supposed to.
result: object = await callback(state_updates)
except Exception as e:
logger.warning("Failed to run module API callback %s: %s", callback, e)
continue
Expand Down
3 changes: 2 additions & 1 deletion synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -1427,7 +1427,7 @@ async def persist_and_notify_client_event(
# Validate a newly added alias or newly added alt_aliases.

original_alias = None
original_alt_aliases: List[str] = []
original_alt_aliases: object = []

original_event_id = event.unsigned.get("replaces_state")
if original_event_id:
Expand Down Expand Up @@ -1455,6 +1455,7 @@ async def persist_and_notify_client_event(
# If the old version of alt_aliases is of an unknown form,
# completely replace it.
if not isinstance(original_alt_aliases, (list, tuple)):
# TODO: check that the original_alt_aliases' entries are all strings
original_alt_aliases = []

# Check that each alias is currently valid.
Expand Down
44 changes: 34 additions & 10 deletions synapse/metrics/background_process_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
Type,
TypeVar,
Union,
cast,
)

from prometheus_client import Metric
from prometheus_client.core import REGISTRY, Counter, Gauge
from typing_extensions import ParamSpec

from twisted.internet import defer

Expand Down Expand Up @@ -256,24 +256,48 @@ async def run() -> Optional[R]:
return defer.ensureDeferred(run())


F = TypeVar("F", bound=Callable[..., Awaitable[Optional[Any]]])
P = ParamSpec("P")


def wrap_as_background_process(desc: str) -> Callable[[F], F]:
"""Decorator that wraps a function that gets called as a background
process.
def wrap_as_background_process(
desc: str,
) -> Callable[
[Callable[P, Awaitable[Optional[R]]]],
Callable[P, "defer.Deferred[Optional[R]]"],
]:
"""Decorator that wraps an asynchronous function `func`, returning a synchronous
decorated function. Calling the decorated version runs `func` as a background
process, forwarding all arguments verbatim.

That is,

@wrap_as_background_process
def func(*args): ...
func(1, 2, third=3)

is equivalent to:

def func(*args): ...
run_as_background_process(func, 1, 2, third=3)

Equivalent to calling the function with `run_as_background_process`
The former can be convenient if `func` needs to be run as a background process in
multiple places.
"""

def wrap_as_background_process_inner(func: F) -> F:
def wrap_as_background_process_inner(
func: Callable[P, Awaitable[Optional[R]]]
) -> Callable[P, "defer.Deferred[Optional[R]]"]:
@wraps(func)
def wrap_as_background_process_inner_2(
*args: Any, **kwargs: Any
*args: P.args, **kwargs: P.kwargs
) -> "defer.Deferred[Optional[R]]":
return run_as_background_process(desc, func, *args, **kwargs)
# type-ignore: mypy is confusing kwargs with the bg_start_span kwarg.
# Argument 4 to "run_as_background_process" has incompatible type
# "**P.kwargs"; expected "bool"
# See https://github.com/python/mypy/issues/8862
return run_as_background_process(desc, func, *args, **kwargs) # type: ignore[arg-type]

return cast(F, wrap_as_background_process_inner_2)
return wrap_as_background_process_inner_2

return wrap_as_background_process_inner

Expand Down
10 changes: 5 additions & 5 deletions tests/storage/test_monthly_active_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,19 @@ def test_reap_monthly_active_users_reserved_users(self):
self.store.user_add_threepid(user, "email", email, now, now)
)

d = self.store.db_pool.runInteraction(
"initialise", self.store._initialise_reserved_users, threepids
self.get_success(
self.store.db_pool.runInteraction(
"initialise", self.store._initialise_reserved_users, threepids
)
)
self.get_success(d)

count = self.get_success(self.store.get_monthly_active_count())
self.assertEqual(count, initial_users)

users = self.get_success(self.store.get_registered_reserved_users())
self.assertEqual(len(users), reserved_user_number)

d = self.store.reap_monthly_active_users()
self.get_success(d)
self.get_success(self.store.reap_monthly_active_users())

count = self.get_success(self.store.get_monthly_active_count())
self.assertEqual(count, self.hs.config.server.max_mau_value)
Expand Down