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

Commit 9999eb2

Browse files
authored
Add type hints to admin and room list handlers. (#8973)
1 parent 14a7371 commit 9999eb2

File tree

5 files changed

+100
-70
lines changed

5 files changed

+100
-70
lines changed

changelog.d/8973.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add type hints to the admin and room list handlers.

mypy.ini

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ files =
2525
synapse/handlers/_base.py,
2626
synapse/handlers/account_data.py,
2727
synapse/handlers/account_validity.py,
28+
synapse/handlers/admin.py,
2829
synapse/handlers/appservice.py,
2930
synapse/handlers/auth.py,
3031
synapse/handlers/cas_handler.py,
@@ -45,6 +46,7 @@ files =
4546
synapse/handlers/read_marker.py,
4647
synapse/handlers/register.py,
4748
synapse/handlers/room.py,
49+
synapse/handlers/room_list.py,
4850
synapse/handlers/room_member.py,
4951
synapse/handlers/room_member_worker.py,
5052
synapse/handlers/saml_handler.py,
@@ -114,6 +116,9 @@ ignore_missing_imports = True
114116
[mypy-h11]
115117
ignore_missing_imports = True
116118

119+
[mypy-msgpack]
120+
ignore_missing_imports = True
121+
117122
[mypy-opentracing]
118123
ignore_missing_imports = True
119124

synapse/handlers/admin.py

+38-25
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,31 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16+
import abc
1617
import logging
17-
from typing import List
18+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set
1819

1920
from synapse.api.constants import Membership
20-
from synapse.events import FrozenEvent
21-
from synapse.types import RoomStreamToken, StateMap
21+
from synapse.events import EventBase
22+
from synapse.types import JsonDict, RoomStreamToken, StateMap, UserID
2223
from synapse.visibility import filter_events_for_client
2324

2425
from ._base import BaseHandler
2526

27+
if TYPE_CHECKING:
28+
from synapse.app.homeserver import HomeServer
29+
2630
logger = logging.getLogger(__name__)
2731

2832

2933
class AdminHandler(BaseHandler):
30-
def __init__(self, hs):
34+
def __init__(self, hs: "HomeServer"):
3135
super().__init__(hs)
3236

3337
self.storage = hs.get_storage()
3438
self.state_store = self.storage.state
3539

36-
async def get_whois(self, user):
40+
async def get_whois(self, user: UserID) -> JsonDict:
3741
connections = []
3842

3943
sessions = await self.store.get_user_ip_and_agents(user)
@@ -53,7 +57,7 @@ async def get_whois(self, user):
5357

5458
return ret
5559

56-
async def get_user(self, user):
60+
async def get_user(self, user: UserID) -> Optional[JsonDict]:
5761
"""Function to get user details"""
5862
ret = await self.store.get_user_by_id(user.to_string())
5963
if ret:
@@ -64,12 +68,12 @@ async def get_user(self, user):
6468
ret["threepids"] = threepids
6569
return ret
6670

67-
async def export_user_data(self, user_id, writer):
71+
async def export_user_data(self, user_id: str, writer: "ExfiltrationWriter") -> Any:
6872
"""Write all data we have on the user to the given writer.
6973
7074
Args:
71-
user_id (str)
72-
writer (ExfiltrationWriter)
75+
user_id: The user ID to fetch data of.
76+
writer: The writer to write to.
7377
7478
Returns:
7579
Resolves when all data for a user has been written.
@@ -128,7 +132,8 @@ async def export_user_data(self, user_id, writer):
128132
from_key = RoomStreamToken(0, 0)
129133
to_key = RoomStreamToken(None, stream_ordering)
130134

131-
written_events = set() # Events that we've processed in this room
135+
# Events that we've processed in this room
136+
written_events = set() # type: Set[str]
132137

133138
# We need to track gaps in the events stream so that we can then
134139
# write out the state at those events. We do this by keeping track
@@ -140,8 +145,8 @@ async def export_user_data(self, user_id, writer):
140145

141146
# The reverse mapping to above, i.e. map from unseen event to events
142147
# that have the unseen event in their prev_events, i.e. the unseen
143-
# events "children". dict[str, set[str]]
144-
unseen_to_child_events = {}
148+
# events "children".
149+
unseen_to_child_events = {} # type: Dict[str, Set[str]]
145150

146151
# We fetch events in the room the user could see by fetching *all*
147152
# events that we have and then filtering, this isn't the most
@@ -197,38 +202,46 @@ async def export_user_data(self, user_id, writer):
197202
return writer.finished()
198203

199204

200-
class ExfiltrationWriter:
205+
class ExfiltrationWriter(metaclass=abc.ABCMeta):
201206
"""Interface used to specify how to write exported data.
202207
"""
203208

204-
def write_events(self, room_id: str, events: List[FrozenEvent]):
209+
@abc.abstractmethod
210+
def write_events(self, room_id: str, events: List[EventBase]) -> None:
205211
"""Write a batch of events for a room.
206212
"""
207-
pass
213+
raise NotImplementedError()
208214

209-
def write_state(self, room_id: str, event_id: str, state: StateMap[FrozenEvent]):
215+
@abc.abstractmethod
216+
def write_state(
217+
self, room_id: str, event_id: str, state: StateMap[EventBase]
218+
) -> None:
210219
"""Write the state at the given event in the room.
211220
212221
This only gets called for backward extremities rather than for each
213222
event.
214223
"""
215-
pass
224+
raise NotImplementedError()
216225

217-
def write_invite(self, room_id: str, event: FrozenEvent, state: StateMap[dict]):
226+
@abc.abstractmethod
227+
def write_invite(
228+
self, room_id: str, event: EventBase, state: StateMap[dict]
229+
) -> None:
218230
"""Write an invite for the room, with associated invite state.
219231
220232
Args:
221-
room_id
222-
event
223-
state: A subset of the state at the
224-
invite, with a subset of the event keys (type, state_key
225-
content and sender)
233+
room_id: The room ID the invite is for.
234+
event: The invite event.
235+
state: A subset of the state at the invite, with a subset of the
236+
event keys (type, state_key content and sender).
226237
"""
238+
raise NotImplementedError()
227239

228-
def finished(self):
240+
@abc.abstractmethod
241+
def finished(self) -> Any:
229242
"""Called when all data has successfully been exported and written.
230243
231244
This functions return value is passed to the caller of
232245
`export_user_data`.
233246
"""
234-
pass
247+
raise NotImplementedError()

synapse/handlers/room_list.py

+51-43
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,22 @@
1515

1616
import logging
1717
from collections import namedtuple
18-
from typing import Any, Dict, Optional
18+
from typing import TYPE_CHECKING, Optional, Tuple
1919

2020
import msgpack
2121
from unpaddedbase64 import decode_base64, encode_base64
2222

2323
from synapse.api.constants import EventTypes, HistoryVisibility, JoinRules
2424
from synapse.api.errors import Codes, HttpResponseException
25-
from synapse.types import ThirdPartyInstanceID
25+
from synapse.types import JsonDict, ThirdPartyInstanceID
2626
from synapse.util.caches.descriptors import cached
2727
from synapse.util.caches.response_cache import ResponseCache
2828

2929
from ._base import BaseHandler
3030

31+
if TYPE_CHECKING:
32+
from synapse.app.homeserver import HomeServer
33+
3134
logger = logging.getLogger(__name__)
3235

3336
REMOTE_ROOM_LIST_POLL_INTERVAL = 60 * 1000
@@ -37,37 +40,38 @@
3740

3841

3942
class RoomListHandler(BaseHandler):
40-
def __init__(self, hs):
43+
def __init__(self, hs: "HomeServer"):
4144
super().__init__(hs)
4245
self.enable_room_list_search = hs.config.enable_room_list_search
43-
self.response_cache = ResponseCache(hs, "room_list")
46+
self.response_cache = ResponseCache(
47+
hs, "room_list"
48+
) # type: ResponseCache[Tuple[Optional[int], Optional[str], ThirdPartyInstanceID]]
4449
self.remote_response_cache = ResponseCache(
4550
hs, "remote_room_list", timeout_ms=30 * 1000
46-
)
51+
) # type: ResponseCache[Tuple[str, Optional[int], Optional[str], bool, Optional[str]]]
4752

4853
async def get_local_public_room_list(
4954
self,
50-
limit=None,
51-
since_token=None,
52-
search_filter=None,
53-
network_tuple=EMPTY_THIRD_PARTY_ID,
54-
from_federation=False,
55-
):
55+
limit: Optional[int] = None,
56+
since_token: Optional[str] = None,
57+
search_filter: Optional[dict] = None,
58+
network_tuple: ThirdPartyInstanceID = EMPTY_THIRD_PARTY_ID,
59+
from_federation: bool = False,
60+
) -> JsonDict:
5661
"""Generate a local public room list.
5762
5863
There are multiple different lists: the main one plus one per third
5964
party network. A client can ask for a specific list or to return all.
6065
6166
Args:
62-
limit (int|None)
63-
since_token (str|None)
64-
search_filter (dict|None)
65-
network_tuple (ThirdPartyInstanceID): Which public list to use.
67+
limit
68+
since_token
69+
search_filter
70+
network_tuple: Which public list to use.
6671
This can be (None, None) to indicate the main list, or a particular
6772
appservice and network id to use an appservice specific one.
6873
Setting to None returns all public rooms across all lists.
69-
from_federation (bool): true iff the request comes from the federation
70-
API
74+
from_federation: true iff the request comes from the federation API
7175
"""
7276
if not self.enable_room_list_search:
7377
return {"chunk": [], "total_room_count_estimate": 0}
@@ -107,10 +111,10 @@ async def _get_public_room_list(
107111
self,
108112
limit: Optional[int] = None,
109113
since_token: Optional[str] = None,
110-
search_filter: Optional[Dict] = None,
114+
search_filter: Optional[dict] = None,
111115
network_tuple: ThirdPartyInstanceID = EMPTY_THIRD_PARTY_ID,
112116
from_federation: bool = False,
113-
) -> Dict[str, Any]:
117+
) -> JsonDict:
114118
"""Generate a public room list.
115119
Args:
116120
limit: Maximum amount of rooms to return.
@@ -131,13 +135,17 @@ async def _get_public_room_list(
131135
if since_token:
132136
batch_token = RoomListNextBatch.from_token(since_token)
133137

134-
bounds = (batch_token.last_joined_members, batch_token.last_room_id)
138+
bounds = (
139+
batch_token.last_joined_members,
140+
batch_token.last_room_id,
141+
) # type: Optional[Tuple[int, str]]
135142
forwards = batch_token.direction_is_forward
143+
has_batch_token = True
136144
else:
137-
batch_token = None
138145
bounds = None
139146

140147
forwards = True
148+
has_batch_token = False
141149

142150
# we request one more than wanted to see if there are more pages to come
143151
probing_limit = limit + 1 if limit is not None else None
@@ -169,7 +177,7 @@ def build_room_entry(room):
169177

170178
results = [build_room_entry(r) for r in results]
171179

172-
response = {}
180+
response = {} # type: JsonDict
173181
num_results = len(results)
174182
if limit is not None:
175183
more_to_come = num_results == probing_limit
@@ -187,7 +195,7 @@ def build_room_entry(room):
187195
initial_entry = results[0]
188196

189197
if forwards:
190-
if batch_token:
198+
if has_batch_token:
191199
# If there was a token given then we assume that there
192200
# must be previous results.
193201
response["prev_batch"] = RoomListNextBatch(
@@ -203,7 +211,7 @@ def build_room_entry(room):
203211
direction_is_forward=True,
204212
).to_token()
205213
else:
206-
if batch_token:
214+
if has_batch_token:
207215
response["next_batch"] = RoomListNextBatch(
208216
last_joined_members=final_entry["num_joined_members"],
209217
last_room_id=final_entry["room_id"],
@@ -293,7 +301,7 @@ async def generate_room_entry(
293301
return None
294302

295303
# Return whether this room is open to federation users or not
296-
create_event = current_state.get((EventTypes.Create, ""))
304+
create_event = current_state[EventTypes.Create, ""]
297305
result["m.federate"] = create_event.content.get("m.federate", True)
298306

299307
name_event = current_state.get((EventTypes.Name, ""))
@@ -336,13 +344,13 @@ async def generate_room_entry(
336344

337345
async def get_remote_public_room_list(
338346
self,
339-
server_name,
340-
limit=None,
341-
since_token=None,
342-
search_filter=None,
343-
include_all_networks=False,
344-
third_party_instance_id=None,
345-
):
347+
server_name: str,
348+
limit: Optional[int] = None,
349+
since_token: Optional[str] = None,
350+
search_filter: Optional[dict] = None,
351+
include_all_networks: bool = False,
352+
third_party_instance_id: Optional[str] = None,
353+
) -> JsonDict:
346354
if not self.enable_room_list_search:
347355
return {"chunk": [], "total_room_count_estimate": 0}
348356

@@ -399,13 +407,13 @@ async def get_remote_public_room_list(
399407

400408
async def _get_remote_list_cached(
401409
self,
402-
server_name,
403-
limit=None,
404-
since_token=None,
405-
search_filter=None,
406-
include_all_networks=False,
407-
third_party_instance_id=None,
408-
):
410+
server_name: str,
411+
limit: Optional[int] = None,
412+
since_token: Optional[str] = None,
413+
search_filter: Optional[dict] = None,
414+
include_all_networks: bool = False,
415+
third_party_instance_id: Optional[str] = None,
416+
) -> JsonDict:
409417
repl_layer = self.hs.get_federation_client()
410418
if search_filter:
411419
# We can't cache when asking for search
@@ -456,24 +464,24 @@ class RoomListNextBatch(
456464
REVERSE_KEY_DICT = {v: k for k, v in KEY_DICT.items()}
457465

458466
@classmethod
459-
def from_token(cls, token):
467+
def from_token(cls, token: str) -> "RoomListNextBatch":
460468
decoded = msgpack.loads(decode_base64(token), raw=False)
461469
return RoomListNextBatch(
462470
**{cls.REVERSE_KEY_DICT[key]: val for key, val in decoded.items()}
463471
)
464472

465-
def to_token(self):
473+
def to_token(self) -> str:
466474
return encode_base64(
467475
msgpack.dumps(
468476
{self.KEY_DICT[key]: val for key, val in self._asdict().items()}
469477
)
470478
)
471479

472-
def copy_and_replace(self, **kwds):
480+
def copy_and_replace(self, **kwds) -> "RoomListNextBatch":
473481
return self._replace(**kwds)
474482

475483

476-
def _matches_room_entry(room_entry, search_filter):
484+
def _matches_room_entry(room_entry: JsonDict, search_filter: dict) -> bool:
477485
if search_filter and search_filter.get("generic_search_term", None):
478486
generic_search_term = search_filter["generic_search_term"].upper()
479487
if generic_search_term in room_entry.get("name", "").upper():

0 commit comments

Comments
 (0)