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

Return read-only collections from @cached methods #13755

Merged
merged 11 commits into from
Feb 10, 2023
1 change: 1 addition & 0 deletions changelog.d/13755.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Re-type hint some collections as read-only.
4 changes: 2 additions & 2 deletions synapse/app/phone_stats_home.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import math
import resource
import sys
from typing import TYPE_CHECKING, List, Sized, Tuple
from typing import TYPE_CHECKING, List, Mapping, Sized, Tuple

from prometheus_client import Gauge

Expand Down Expand Up @@ -194,7 +194,7 @@ def performance_stats_init() -> None:
@wrap_as_background_process("generate_monthly_active_users")
async def generate_monthly_active_users() -> None:
current_mau_count = 0
current_mau_count_by_service = {}
current_mau_count_by_service: Mapping[str, int] = {}
reserved_users: Sized = ()
store = hs.get_datastores().main
if hs.config.server.limit_usage_by_mau or hs.config.server.mau_stats_only:
Expand Down
6 changes: 3 additions & 3 deletions synapse/config/room_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Any, List
from typing import Any, Collection

from matrix_common.regex import glob_to_regex

Expand Down Expand Up @@ -70,7 +70,7 @@ def is_alias_creation_allowed(self, user_id: str, room_id: str, alias: str) -> b
return False

def is_publishing_room_allowed(
self, user_id: str, room_id: str, aliases: List[str]
self, user_id: str, room_id: str, aliases: Collection[str]
) -> bool:
"""Checks if the given user is allowed to publish the room

Expand Down Expand Up @@ -122,7 +122,7 @@ def __init__(self, option_name: str, rule: JsonDict):
except Exception as e:
raise ConfigError("Failed to parse glob into regex") from e

def matches(self, user_id: str, room_id: str, aliases: List[str]) -> bool:
def matches(self, user_id: str, room_id: str, aliases: Collection[str]) -> bool:
"""Tests if this rule matches the given user_id, room_id and aliases.

Args:
Expand Down
5 changes: 3 additions & 2 deletions synapse/handlers/directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import logging
import string
from typing import TYPE_CHECKING, Iterable, List, Optional
from typing import TYPE_CHECKING, Iterable, List, Optional, Sequence

from synapse.api.constants import MAX_ALIAS_LENGTH, EventTypes
from synapse.api.errors import (
Expand Down Expand Up @@ -483,6 +483,7 @@ async def edit_published_room_list(
)
)
if canonical_alias:
room_aliases = list(room_aliases)
room_aliases.append(canonical_alias)
clokep marked this conversation as resolved.
Show resolved Hide resolved

if not self.config.roomdirectory.is_publishing_room_allowed(
Expand Down Expand Up @@ -525,7 +526,7 @@ async def edit_published_appservice_room_list(

async def get_aliases_for_room(
self, requester: Requester, room_id: str
) -> List[str]:
) -> Sequence[str]:
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
"""
Get a list of the aliases that currently point to this room on this server
"""
Expand Down
4 changes: 2 additions & 2 deletions synapse/handlers/receipts.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple
from typing import TYPE_CHECKING, Iterable, List, Optional, Sequence, Tuple

from synapse.api.constants import EduTypes, ReceiptTypes
from synapse.appservice import ApplicationService
Expand Down Expand Up @@ -174,7 +174,7 @@ def __init__(self, hs: "HomeServer"):

@staticmethod
def filter_out_private_receipts(
rooms: List[JsonDict], user_id: str
rooms: Sequence[JsonDict], user_id: str
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
) -> List[JsonDict]:
"""
Filters a list of serialized receipts (as returned by /sync and /initialSync)
Expand Down
2 changes: 1 addition & 1 deletion synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,6 @@ async def shutdown_room(
return {
"kicked_users": kicked_users,
"failed_to_kick_users": failed_to_kick_users,
"local_aliases": aliases_for_room,
"local_aliases": list(aliases_for_room),
"new_room_id": new_room_id,
}
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 7 additions & 5 deletions synapse/handlers/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -1377,7 +1377,7 @@ async def generate_sync_result(
one_time_key_counts = await self.store.count_e2e_one_time_keys(
user_id, device_id
)
unused_fallback_key_types = (
unused_fallback_key_types = list(
await self.store.get_e2e_unused_fallback_key_types(user_id, device_id)
)
Comment on lines +1522 to 1524
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This goes straight into the SyncResult and is pretty much only going to be JSON-serialized from here on.
Having to take a copy to make mypy happy is unfortunate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least it's a shallow copy 🤷

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be curious of the error here? Is something in our code unhappy or is it a type hint of like json.dump?

I think it'd be OK to add a cast with a comment explaining it is for performance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a type hint problem. Only Lists and Tuples are JSON-serializable, except they're mutable types. I would have updated the definition of SyncResult otherwise.


Expand Down Expand Up @@ -1573,7 +1573,7 @@ async def _generate_sync_entry_for_to_device(

async def _generate_sync_entry_for_account_data(
self, sync_result_builder: "SyncResultBuilder"
) -> Dict[str, Dict[str, JsonDict]]:
) -> Mapping[str, Mapping[str, JsonDict]]:
"""Generates the account data portion of the sync response.

Account data (called "Client Config" in the spec) can be set either globally
Expand Down Expand Up @@ -1608,6 +1608,7 @@ async def _generate_sync_entry_for_account_data(
)

if push_rules_changed:
global_account_data = dict(global_account_data)
global_account_data["m.push_rules"] = await self.push_rules_for_user(
sync_config.user
)
Expand All @@ -1617,6 +1618,7 @@ async def _generate_sync_entry_for_account_data(
account_data_by_room,
) = await self.store.get_account_data_for_user(sync_config.user.to_string())

global_account_data = dict(global_account_data)
global_account_data["m.push_rules"] = await self.push_rules_for_user(
sync_config.user
)
clokep marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -1693,7 +1695,7 @@ async def _generate_sync_entry_for_presence(
async def _generate_sync_entry_for_rooms(
self,
sync_result_builder: "SyncResultBuilder",
account_data_by_room: Dict[str, Dict[str, JsonDict]],
account_data_by_room: Mapping[str, Mapping[str, JsonDict]],
) -> Tuple[Set[str], Set[str], Set[str], Set[str]]:
"""Generates the rooms portion of the sync response. Populates the
`sync_result_builder` with the result.
Expand Down Expand Up @@ -2170,8 +2172,8 @@ async def _generate_room_entry(
sync_result_builder: "SyncResultBuilder",
room_builder: "RoomSyncResultBuilder",
ephemeral: List[JsonDict],
tags: Optional[Dict[str, Dict[str, Any]]],
account_data: Dict[str, JsonDict],
tags: Optional[Mapping[str, Mapping[str, Any]]],
account_data: Mapping[str, JsonDict],
always_include: bool = False,
) -> None:
"""Populates the `joined` and `archived` section of `sync_result_builder`
Expand Down
4 changes: 2 additions & 2 deletions synapse/push/bulk_push_rule_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
import logging
from typing import (
TYPE_CHECKING,
AbstractSet,
Collection,
Dict,
Iterable,
List,
Mapping,
Optional,
Set,
Tuple,
Union,
)
Expand Down Expand Up @@ -199,7 +199,7 @@ async def _get_power_levels_and_sender_level(

async def _get_mutual_relations(
self, event: EventBase, rules: Iterable[Tuple[PushRule, bool]]
) -> Dict[str, Set[Tuple[str, str]]]:
) -> Dict[str, AbstractSet[Tuple[str, str]]]:
"""
Fetch event metadata for events which related to the same event as the given event.

Expand Down
4 changes: 2 additions & 2 deletions synapse/push/push_rule_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
import logging
import re
from typing import (
AbstractSet,
Any,
Dict,
List,
Mapping,
Optional,
Pattern,
Sequence,
Set,
Tuple,
Union,
)
Expand Down Expand Up @@ -131,7 +131,7 @@ def __init__(
room_member_count: int,
sender_power_level: int,
power_levels: Dict[str, Union[int, Dict[str, int]]],
relations: Dict[str, Set[Tuple[str, str]]],
relations: Dict[str, AbstractSet[Tuple[str, str]]],
relations_match_enabled: bool,
):
self._event = event
Expand Down
2 changes: 1 addition & 1 deletion synapse/state/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ async def compute_state_after_events(
return await ret.get_state(self._state_storage_controller, state_filter)

async def get_current_user_ids_in_room(
self, room_id: str, latest_event_ids: List[str]
self, room_id: str, latest_event_ids: Collection[str]
) -> Set[str]:
"""
Get the users IDs who are currently in a room.
Expand Down
5 changes: 3 additions & 2 deletions synapse/storage/controllers/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
List,
Mapping,
Optional,
Sequence,
Tuple,
)

Expand Down Expand Up @@ -523,7 +524,7 @@ async def get_current_state_event(
)
return state_map.get(key)

async def get_current_hosts_in_room(self, room_id: str) -> List[str]:
async def get_current_hosts_in_room(self, room_id: str) -> Sequence[str]:
"""Get current hosts in room based on current state."""

await self._partial_state_room_tracker.await_full_state(room_id)
Expand All @@ -532,7 +533,7 @@ async def get_current_hosts_in_room(self, room_id: str) -> List[str]:

async def get_users_in_room_with_profiles(
self, room_id: str
) -> Dict[str, ProfileInfo]:
) -> Mapping[str, ProfileInfo]:
"""
Get the current users in the room with their profiles.
If the room is currently partial-stated, this will block until the room has
Expand Down
7 changes: 4 additions & 3 deletions synapse/storage/databases/main/account_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
FrozenSet,
Iterable,
List,
Mapping,
Optional,
Tuple,
cast,
Expand Down Expand Up @@ -132,7 +133,7 @@ def get_max_account_data_stream_id(self) -> int:
@cached()
async def get_account_data_for_user(
self, user_id: str
) -> Tuple[Dict[str, JsonDict], Dict[str, Dict[str, JsonDict]]]:
) -> Tuple[Mapping[str, JsonDict], Mapping[str, Mapping[str, JsonDict]]]:
"""Get all the client account_data for a user.

Args:
Expand Down Expand Up @@ -198,7 +199,7 @@ async def get_global_account_data_by_type_for_user(
@cached(num_args=2, tree=True)
async def get_account_data_for_room(
self, user_id: str, room_id: str
) -> Dict[str, JsonDict]:
) -> Mapping[str, JsonDict]:
"""Get all the client account_data for a user for a room.

Args:
Expand Down Expand Up @@ -327,7 +328,7 @@ def get_updated_room_account_data_txn(

async def get_updated_account_data_for_user(
self, user_id: str, stream_id: int
) -> Tuple[Dict[str, JsonDict], Dict[str, Dict[str, JsonDict]]]:
) -> Tuple[Mapping[str, JsonDict], Mapping[str, Mapping[str, JsonDict]]]:
DMRobertson marked this conversation as resolved.
Show resolved Hide resolved
"""Get all the client account_data for a that's changed for a user

Args:
Expand Down
14 changes: 12 additions & 2 deletions synapse/storage/databases/main/appservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@
# limitations under the License.
import logging
import re
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Pattern, Tuple, cast
from typing import (
TYPE_CHECKING,
Any,
Dict,
List,
Optional,
Pattern,
Sequence,
Tuple,
cast,
)

from synapse.appservice import (
ApplicationService,
Expand Down Expand Up @@ -156,7 +166,7 @@ async def get_app_service_users_in_room(
room_id: str,
app_service: "ApplicationService",
cache_context: _CacheContext,
) -> List[str]:
) -> Sequence[str]:
users_in_room = await self.get_users_in_room(
room_id, on_invalidate=cache_context.invalidate
)
Expand Down
11 changes: 7 additions & 4 deletions synapse/storage/databases/main/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Dict,
Iterable,
List,
Mapping,
Optional,
Set,
Tuple,
Expand Down Expand Up @@ -135,7 +136,9 @@ def __init__(
self._prune_old_outbound_device_pokes, 60 * 60 * 1000
)

async def count_devices_by_users(self, user_ids: Optional[List[str]] = None) -> int:
async def count_devices_by_users(
self, user_ids: Optional[Collection[str]] = None
) -> int:
"""Retrieve number of all devices of given users.
Only returns number of devices that are not marked as hidden.

Expand All @@ -146,7 +149,7 @@ async def count_devices_by_users(self, user_ids: Optional[List[str]] = None) ->
"""

def count_devices_by_users_txn(
txn: LoggingTransaction, user_ids: List[str]
txn: LoggingTransaction, user_ids: Collection[str]
) -> int:
sql = """
SELECT count(*)
Expand Down Expand Up @@ -706,7 +709,7 @@ async def get_user_devices_from_cache(
device = await self._get_cached_user_device(user_id, device_id)
results.setdefault(user_id, {})[device_id] = device
else:
results[user_id] = await self.get_cached_devices_for_user(user_id)
results[user_id] = dict(await self.get_cached_devices_for_user(user_id))
clokep marked this conversation as resolved.
Show resolved Hide resolved

set_tag("in_cache", str(results))
set_tag("not_in_cache", str(user_ids_not_in_cache))
Expand All @@ -724,7 +727,7 @@ async def _get_cached_user_device(self, user_id: str, device_id: str) -> JsonDic
return db_to_json(content)

@cached()
async def get_cached_devices_for_user(self, user_id: str) -> Dict[str, JsonDict]:
async def get_cached_devices_for_user(self, user_id: str) -> Mapping[str, JsonDict]:
devices = await self.db_pool.simple_select_list(
table="device_lists_remote_cache",
keyvalues={"user_id": user_id},
Expand Down
4 changes: 2 additions & 2 deletions synapse/storage/databases/main/directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Iterable, List, Optional, Tuple
from typing import Iterable, List, Optional, Sequence, Tuple

import attr

Expand Down Expand Up @@ -74,7 +74,7 @@ async def get_room_alias_creator(self, room_alias: str) -> str:
)

@cached(max_entries=5000)
async def get_aliases_for_room(self, room_id: str) -> List[str]:
async def get_aliases_for_room(self, room_id: str) -> Sequence[str]:
return await self.db_pool.simple_select_onecol(
"room_aliases",
{"room_id": room_id},
Expand Down
Loading