diff --git a/synapse/appservice/api.py b/synapse/appservice/api.py
index adc6b074da..d19f8dd996 100644
--- a/synapse/appservice/api.py
+++ b/synapse/appservice/api.py
@@ -17,6 +17,7 @@ import urllib.parse
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
@@ -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
diff --git a/synapse/config/appservice.py b/synapse/config/appservice.py
index b13cc6bb6e..24498e7944 100644
--- a/synapse/config/appservice.py
+++ b/synapse/config/appservice.py
@@ -55,7 +55,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.
+ logger.warning("Expected %s to be a list of AS config files.", config_files) # type: ignore[unreachable]
return []
# Dicts of value -> filename
diff --git a/synapse/events/presence_router.py b/synapse/events/presence_router.py
index a58f313e8b..98555c8c0c 100644
--- a/synapse/events/presence_router.py
+++ b/synapse/events/presence_router.py
@@ -147,7 +147,9 @@ class PresenceRouter:
# 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
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 95a89ac01f..c28b792e6f 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -1427,7 +1427,7 @@ class EventCreationHandler:
# 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:
@@ -1455,6 +1455,7 @@ class EventCreationHandler:
# 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.
diff --git a/synapse/metrics/background_process_metrics.py b/synapse/metrics/background_process_metrics.py
index f61396bb79..298809742a 100644
--- a/synapse/metrics/background_process_metrics.py
+++ b/synapse/metrics/background_process_metrics.py
@@ -28,11 +28,11 @@ from typing import (
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
@@ -256,24 +256,48 @@ def run_as_background_process(
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
|