|
23 | 23 | import logging
|
24 | 24 | from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, cast
|
25 | 25 |
|
| 26 | +from typing_extensions import TypeAlias |
| 27 | + |
26 | 28 | from twisted.internet.interfaces import IOpenSSLContextFactory
|
27 | 29 | from twisted.internet.tcp import Port
|
28 | 30 | from twisted.web.iweb import IPolicyForHTTPS
|
|
142 | 144 | from synapse.handlers.saml import SamlHandler
|
143 | 145 |
|
144 | 146 |
|
145 |
| -T = TypeVar("T") |
| 147 | +# The annotation for `cache_in_self` used to be |
| 148 | +# def (builder: Callable[["HomeServer"],T]) -> Callable[["HomeServer"],T] |
| 149 | +# which mypy was happy with. |
| 150 | +# |
| 151 | +# But PyCharm was confused by this. If `foo` was decorated by `@cache_in_self`, then |
| 152 | +# an expression like `hs.foo()` |
| 153 | +# |
| 154 | +# - would erroneously warn that we hadn't provided a `hs` argument to foo (PyCharm |
| 155 | +# confused about boundmethods and unbound methods?), and |
| 156 | +# - would be considered to have type `Any`, making for a poor autocomplete and |
| 157 | +# cross-referencing experience. |
| 158 | +# |
| 159 | +# Instead, use a typevar `F` to express that `@cache_in_self` returns exactly the |
| 160 | +# same type it receives. This isn't strictly true [*], but it's more than good |
| 161 | +# enough to keep PyCharm and mypy happy. |
| 162 | +# |
| 163 | +# [*]: (e.g. `builder` could be an object with a __call__ attribute rather than a |
| 164 | +# types.FunctionType instance, whereas the return value is always a |
| 165 | +# types.FunctionType instance.) |
| 166 | + |
| 167 | +T: TypeAlias = object |
| 168 | +F = TypeVar("F", bound=Callable[["HomeServer"], T]) |
146 | 169 |
|
147 | 170 |
|
148 |
| -def cache_in_self(builder: Callable[["HomeServer"], T]) -> Callable[["HomeServer"], T]: |
| 171 | +def cache_in_self(builder: F) -> F: |
149 | 172 | """Wraps a function called e.g. `get_foo`, checking if `self.foo` exists and
|
150 | 173 | returning if so. If not, calls the given function and sets `self.foo` to it.
|
151 | 174 |
|
@@ -183,7 +206,7 @@ def _get(self: "HomeServer") -> T:
|
183 | 206 |
|
184 | 207 | return dep
|
185 | 208 |
|
186 |
| - return _get |
| 209 | + return cast(F, _get) |
187 | 210 |
|
188 | 211 |
|
189 | 212 | class HomeServer(metaclass=abc.ABCMeta):
|
|
0 commit comments