forked from MirrorHub/synapse
Give PyCharm some help with @cache_in_self
(#15238)
* Give PyCharm some help with `@cache_in_self` * Changelog * Fix import for old python versions
This commit is contained in:
parent
caf43c3d7c
commit
ce54477f6f
2 changed files with 27 additions and 3 deletions
1
changelog.d/15238.misc
Normal file
1
changelog.d/15238.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Improve type hints.
|
|
@ -23,6 +23,8 @@ import functools
|
|||
import logging
|
||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, cast
|
||||
|
||||
from typing_extensions import TypeAlias
|
||||
|
||||
from twisted.internet.interfaces import IOpenSSLContextFactory
|
||||
from twisted.internet.tcp import Port
|
||||
from twisted.web.iweb import IPolicyForHTTPS
|
||||
|
@ -142,10 +144,31 @@ if TYPE_CHECKING:
|
|||
from synapse.handlers.saml import SamlHandler
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
# The annotation for `cache_in_self` used to be
|
||||
# def (builder: Callable[["HomeServer"],T]) -> Callable[["HomeServer"],T]
|
||||
# which mypy was happy with.
|
||||
#
|
||||
# But PyCharm was confused by this. If `foo` was decorated by `@cache_in_self`, then
|
||||
# an expression like `hs.foo()`
|
||||
#
|
||||
# - would erroneously warn that we hadn't provided a `hs` argument to foo (PyCharm
|
||||
# confused about boundmethods and unbound methods?), and
|
||||
# - would be considered to have type `Any`, making for a poor autocomplete and
|
||||
# cross-referencing experience.
|
||||
#
|
||||
# Instead, use a typevar `F` to express that `@cache_in_self` returns exactly the
|
||||
# same type it receives. This isn't strictly true [*], but it's more than good
|
||||
# enough to keep PyCharm and mypy happy.
|
||||
#
|
||||
# [*]: (e.g. `builder` could be an object with a __call__ attribute rather than a
|
||||
# types.FunctionType instance, whereas the return value is always a
|
||||
# types.FunctionType instance.)
|
||||
|
||||
T: TypeAlias = object
|
||||
F = TypeVar("F", bound=Callable[["HomeServer"], T])
|
||||
|
||||
|
||||
def cache_in_self(builder: Callable[["HomeServer"], T]) -> Callable[["HomeServer"], T]:
|
||||
def cache_in_self(builder: F) -> F:
|
||||
"""Wraps a function called e.g. `get_foo`, checking if `self.foo` exists and
|
||||
returning if so. If not, calls the given function and sets `self.foo` to it.
|
||||
|
||||
|
@ -183,7 +206,7 @@ def cache_in_self(builder: Callable[["HomeServer"], T]) -> Callable[["HomeServer
|
|||
|
||||
return dep
|
||||
|
||||
return _get
|
||||
return cast(F, _get)
|
||||
|
||||
|
||||
class HomeServer(metaclass=abc.ABCMeta):
|
||||
|
|
Loading…
Reference in a new issue