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
|
import logging
|
||||||
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, cast
|
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.interfaces import IOpenSSLContextFactory
|
||||||
from twisted.internet.tcp import Port
|
from twisted.internet.tcp import Port
|
||||||
from twisted.web.iweb import IPolicyForHTTPS
|
from twisted.web.iweb import IPolicyForHTTPS
|
||||||
|
@ -142,10 +144,31 @@ if TYPE_CHECKING:
|
||||||
from synapse.handlers.saml import SamlHandler
|
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
|
"""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.
|
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 dep
|
||||||
|
|
||||||
return _get
|
return cast(F, _get)
|
||||||
|
|
||||||
|
|
||||||
class HomeServer(metaclass=abc.ABCMeta):
|
class HomeServer(metaclass=abc.ABCMeta):
|
||||||
|
|
Loading…
Reference in a new issue