Convert all namedtuples to attrs. (#11665)

To improve type hints throughout the code.
This commit is contained in:
Patrick Cloke 2021-12-30 13:47:12 -05:00 committed by GitHub
parent 07a3b5daba
commit cbd82d0b2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 231 additions and 206 deletions

1
changelog.d/11665.misc Normal file
View file

@ -0,0 +1 @@
Convert `namedtuples` to `attrs`.

View file

@ -351,8 +351,7 @@ class Filter:
True if the event matches the filter. True if the event matches the filter.
""" """
# We usually get the full "events" as dictionaries coming through, # We usually get the full "events" as dictionaries coming through,
# except for presence which actually gets passed around as its own # except for presence which actually gets passed around as its own type.
# namedtuple type.
if isinstance(event, UserPresenceState): if isinstance(event, UserPresenceState):
user_id = event.user_id user_id = event.user_id
field_matchers = { field_matchers = {

View file

@ -14,10 +14,11 @@
import logging import logging
import os import os
from collections import namedtuple
from typing import Dict, List, Tuple from typing import Dict, List, Tuple
from urllib.request import getproxies_environment # type: ignore from urllib.request import getproxies_environment # type: ignore
import attr
from synapse.config.server import DEFAULT_IP_RANGE_BLACKLIST, generate_ip_set from synapse.config.server import DEFAULT_IP_RANGE_BLACKLIST, generate_ip_set
from synapse.python_dependencies import DependencyException, check_requirements from synapse.python_dependencies import DependencyException, check_requirements
from synapse.types import JsonDict from synapse.types import JsonDict
@ -44,18 +45,20 @@ THUMBNAIL_SIZE_YAML = """\
HTTP_PROXY_SET_WARNING = """\ HTTP_PROXY_SET_WARNING = """\
The Synapse config url_preview_ip_range_blacklist will be ignored as an HTTP(s) proxy is configured.""" The Synapse config url_preview_ip_range_blacklist will be ignored as an HTTP(s) proxy is configured."""
ThumbnailRequirement = namedtuple(
"ThumbnailRequirement", ["width", "height", "method", "media_type"]
)
MediaStorageProviderConfig = namedtuple( @attr.s(frozen=True, slots=True, auto_attribs=True)
"MediaStorageProviderConfig", class ThumbnailRequirement:
( width: int
"store_local", # Whether to store newly uploaded local files height: int
"store_remote", # Whether to store newly downloaded remote files method: str
"store_synchronous", # Whether to wait for successful storage for local uploads media_type: str
),
)
@attr.s(frozen=True, slots=True, auto_attribs=True)
class MediaStorageProviderConfig:
store_local: bool # Whether to store newly uploaded local files
store_remote: bool # Whether to store newly downloaded remote files
store_synchronous: bool # Whether to wait for successful storage for local uploads
def parse_thumbnail_requirements( def parse_thumbnail_requirements(
@ -66,11 +69,10 @@ def parse_thumbnail_requirements(
method, and thumbnail media type to precalculate method, and thumbnail media type to precalculate
Args: Args:
thumbnail_sizes(list): List of dicts with "width", "height", and thumbnail_sizes: List of dicts with "width", "height", and "method" keys
"method" keys
Returns: Returns:
Dictionary mapping from media type string to list of Dictionary mapping from media type string to list of ThumbnailRequirement.
ThumbnailRequirement tuples.
""" """
requirements: Dict[str, List[ThumbnailRequirement]] = {} requirements: Dict[str, List[ThumbnailRequirement]] = {}
for size in thumbnail_sizes: for size in thumbnail_sizes:

View file

@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import logging import logging
from collections import namedtuple
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from synapse.api.constants import MAX_DEPTH, EventContentFields, EventTypes, Membership from synapse.api.constants import MAX_DEPTH, EventContentFields, EventTypes, Membership
@ -104,10 +103,6 @@ class FederationBase:
return pdu return pdu
class PduToCheckSig(namedtuple("PduToCheckSig", ["pdu", "sender_domain", "deferreds"])):
pass
async def _check_sigs_on_pdu( async def _check_sigs_on_pdu(
keyring: Keyring, room_version: RoomVersion, pdu: EventBase keyring: Keyring, room_version: RoomVersion, pdu: EventBase
) -> None: ) -> None:

View file

@ -30,7 +30,6 @@ Events are replicated via a separate events stream.
""" """
import logging import logging
from collections import namedtuple
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Dict, Dict,
@ -43,6 +42,7 @@ from typing import (
Type, Type,
) )
import attr
from sortedcontainers import SortedDict from sortedcontainers import SortedDict
from synapse.api.presence import UserPresenceState from synapse.api.presence import UserPresenceState
@ -382,13 +382,11 @@ class BaseFederationRow:
raise NotImplementedError() raise NotImplementedError()
class PresenceDestinationsRow( @attr.s(slots=True, frozen=True, auto_attribs=True)
BaseFederationRow, class PresenceDestinationsRow(BaseFederationRow):
namedtuple( state: UserPresenceState
"PresenceDestinationsRow", destinations: List[str]
("state", "destinations"), # UserPresenceState # list[str]
),
):
TypeId = "pd" TypeId = "pd"
@staticmethod @staticmethod
@ -404,17 +402,15 @@ class PresenceDestinationsRow(
buff.presence_destinations.append((self.state, self.destinations)) buff.presence_destinations.append((self.state, self.destinations))
class KeyedEduRow( @attr.s(slots=True, frozen=True, auto_attribs=True)
BaseFederationRow, class KeyedEduRow(BaseFederationRow):
namedtuple(
"KeyedEduRow",
("key", "edu"), # tuple(str) - the edu key passed to send_edu # Edu
),
):
"""Streams EDUs that have an associated key that is ued to clobber. For example, """Streams EDUs that have an associated key that is ued to clobber. For example,
typing EDUs clobber based on room_id. typing EDUs clobber based on room_id.
""" """
key: Tuple[str, ...] # the edu key passed to send_edu
edu: Edu
TypeId = "k" TypeId = "k"
@staticmethod @staticmethod
@ -428,9 +424,12 @@ class KeyedEduRow(
buff.keyed_edus.setdefault(self.edu.destination, {})[self.key] = self.edu buff.keyed_edus.setdefault(self.edu.destination, {})[self.key] = self.edu
class EduRow(BaseFederationRow, namedtuple("EduRow", ("edu",))): # Edu @attr.s(slots=True, frozen=True, auto_attribs=True)
class EduRow(BaseFederationRow):
"""Streams EDUs that don't have keys. See KeyedEduRow""" """Streams EDUs that don't have keys. See KeyedEduRow"""
edu: Edu
TypeId = "e" TypeId = "e"
@staticmethod @staticmethod
@ -453,14 +452,14 @@ _rowtypes: Tuple[Type[BaseFederationRow], ...] = (
TypeToRow = {Row.TypeId: Row for Row in _rowtypes} TypeToRow = {Row.TypeId: Row for Row in _rowtypes}
ParsedFederationStreamData = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"ParsedFederationStreamData", class ParsedFederationStreamData:
( # list of tuples of UserPresenceState and destinations
"presence_destinations", # list of tuples of UserPresenceState and destinations presence_destinations: List[Tuple[UserPresenceState, List[str]]]
"keyed_edus", # dict of destination -> { key -> Edu } # dict of destination -> { key -> Edu }
"edus", # dict of destination -> [Edu] keyed_edus: Dict[str, Dict[Tuple[str, ...], Edu]]
), # dict of destination -> [Edu]
) edus: Dict[str, List[Edu]]
def process_rows_for_federation( def process_rows_for_federation(

View file

@ -462,9 +462,9 @@ class ApplicationServicesHandler:
Args: Args:
room_alias: The room alias to query. room_alias: The room alias to query.
Returns: Returns:
namedtuple: with keys "room_id" and "servers" or None if no RoomAliasMapping or None if no association can be found.
association can be found.
""" """
room_alias_str = room_alias.to_string() room_alias_str = room_alias.to_string()
services = self.store.get_app_services() services = self.store.get_app_services()

View file

@ -278,13 +278,15 @@ class DirectoryHandler:
users = await self.store.get_users_in_room(room_id) users = await self.store.get_users_in_room(room_id)
extra_servers = {get_domain_from_id(u) for u in users} extra_servers = {get_domain_from_id(u) for u in users}
servers = set(extra_servers) | set(servers) servers_set = set(extra_servers) | set(servers)
# If this server is in the list of servers, return it first. # If this server is in the list of servers, return it first.
if self.server_name in servers: if self.server_name in servers_set:
servers = [self.server_name] + [s for s in servers if s != self.server_name] servers = [self.server_name] + [
s for s in servers_set if s != self.server_name
]
else: else:
servers = list(servers) servers = list(servers_set)
return {"room_id": room_id, "servers": servers} return {"room_id": room_id, "servers": servers}

View file

@ -13,9 +13,9 @@
# limitations under the License. # limitations under the License.
import logging import logging
from collections import namedtuple
from typing import TYPE_CHECKING, Any, Optional, Tuple from typing import TYPE_CHECKING, Any, Optional, Tuple
import attr
import msgpack import msgpack
from unpaddedbase64 import decode_base64, encode_base64 from unpaddedbase64 import decode_base64, encode_base64
@ -474,16 +474,12 @@ class RoomListHandler:
) )
class RoomListNextBatch( @attr.s(slots=True, frozen=True, auto_attribs=True)
namedtuple( class RoomListNextBatch:
"RoomListNextBatch", last_joined_members: int # The count to get rooms after/before
( last_room_id: str # The room_id to get rooms after/before
"last_joined_members", # The count to get rooms after/before direction_is_forward: bool # True if this is a next_batch, false if prev_batch
"last_room_id", # The room_id to get rooms after/before
"direction_is_forward", # Bool if this is a next_batch, false if prev_batch
),
)
):
KEY_DICT = { KEY_DICT = {
"last_joined_members": "m", "last_joined_members": "m",
"last_room_id": "r", "last_room_id": "r",
@ -502,12 +498,12 @@ class RoomListNextBatch(
def to_token(self) -> str: def to_token(self) -> str:
return encode_base64( return encode_base64(
msgpack.dumps( msgpack.dumps(
{self.KEY_DICT[key]: val for key, val in self._asdict().items()} {self.KEY_DICT[key]: val for key, val in attr.asdict(self).items()}
) )
) )
def copy_and_replace(self, **kwds: Any) -> "RoomListNextBatch": def copy_and_replace(self, **kwds: Any) -> "RoomListNextBatch":
return self._replace(**kwds) return attr.evolve(self, **kwds)
def _matches_room_entry(room_entry: JsonDict, search_filter: dict) -> bool: def _matches_room_entry(room_entry: JsonDict, search_filter: dict) -> bool:

View file

@ -13,9 +13,10 @@
# limitations under the License. # limitations under the License.
import logging import logging
import random import random
from collections import namedtuple
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple
import attr
from synapse.api.errors import AuthError, ShadowBanError, SynapseError from synapse.api.errors import AuthError, ShadowBanError, SynapseError
from synapse.appservice import ApplicationService from synapse.appservice import ApplicationService
from synapse.metrics.background_process_metrics import ( from synapse.metrics.background_process_metrics import (
@ -37,7 +38,10 @@ logger = logging.getLogger(__name__)
# A tiny object useful for storing a user's membership in a room, as a mapping # A tiny object useful for storing a user's membership in a room, as a mapping
# key # key
RoomMember = namedtuple("RoomMember", ("room_id", "user_id")) @attr.s(slots=True, frozen=True, auto_attribs=True)
class RoomMember:
room_id: str
user_id: str
# How often we expect remote servers to resend us presence. # How often we expect remote servers to resend us presence.
@ -119,7 +123,7 @@ class FollowerTypingHandler:
self.wheel_timer.insert(now=now, obj=member, then=now + 60 * 1000) self.wheel_timer.insert(now=now, obj=member, then=now + 60 * 1000)
def is_typing(self, member: RoomMember) -> bool: def is_typing(self, member: RoomMember) -> bool:
return member.user_id in self._room_typing.get(member.room_id, []) return member.user_id in self._room_typing.get(member.room_id, set())
async def _push_remote(self, member: RoomMember, typing: bool) -> None: async def _push_remote(self, member: RoomMember, typing: bool) -> None:
if not self.federation: if not self.federation:
@ -166,9 +170,9 @@ class FollowerTypingHandler:
for row in rows: for row in rows:
self._room_serials[row.room_id] = token self._room_serials[row.room_id] = token
prev_typing = set(self._room_typing.get(row.room_id, [])) prev_typing = self._room_typing.get(row.room_id, set())
now_typing = set(row.user_ids) now_typing = set(row.user_ids)
self._room_typing[row.room_id] = row.user_ids self._room_typing[row.room_id] = now_typing
if self.federation: if self.federation:
run_as_background_process( run_as_background_process(

View file

@ -14,7 +14,6 @@
# limitations under the License. # limitations under the License.
import abc import abc
import collections
import html import html
import logging import logging
import types import types
@ -37,6 +36,7 @@ from typing import (
Union, Union,
) )
import attr
import jinja2 import jinja2
from canonicaljson import encode_canonical_json from canonicaljson import encode_canonical_json
from typing_extensions import Protocol from typing_extensions import Protocol
@ -354,9 +354,11 @@ class DirectServeJsonResource(_AsyncResource):
return_json_error(f, request) return_json_error(f, request)
_PathEntry = collections.namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"_PathEntry", ["pattern", "callback", "servlet_classname"] class _PathEntry:
) pattern: Pattern
callback: ServletCallback
servlet_classname: str
class JsonResource(DirectServeJsonResource): class JsonResource(DirectServeJsonResource):

View file

@ -15,7 +15,6 @@
import heapq import heapq
import logging import logging
from collections import namedtuple
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
@ -30,6 +29,7 @@ from typing import (
import attr import attr
from synapse.replication.http.streams import ReplicationGetStreamUpdates from synapse.replication.http.streams import ReplicationGetStreamUpdates
from synapse.types import JsonDict
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.server import HomeServer from synapse.server import HomeServer
@ -226,17 +226,14 @@ class BackfillStream(Stream):
or it went from being an outlier to not. or it went from being an outlier to not.
""" """
BackfillStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"BackfillStreamRow", class BackfillStreamRow:
( event_id: str
"event_id", # str room_id: str
"room_id", # str type: str
"type", # str state_key: Optional[str]
"state_key", # str, optional redacts: Optional[str]
"redacts", # str, optional relates_to: Optional[str]
"relates_to", # str, optional
),
)
NAME = "backfill" NAME = "backfill"
ROW_TYPE = BackfillStreamRow ROW_TYPE = BackfillStreamRow
@ -256,18 +253,15 @@ class BackfillStream(Stream):
class PresenceStream(Stream): class PresenceStream(Stream):
PresenceStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"PresenceStreamRow", class PresenceStreamRow:
( user_id: str
"user_id", # str state: str
"state", # str last_active_ts: int
"last_active_ts", # int last_federation_update_ts: int
"last_federation_update_ts", # int last_user_sync_ts: int
"last_user_sync_ts", # int status_msg: str
"status_msg", # str currently_active: bool
"currently_active", # bool
),
)
NAME = "presence" NAME = "presence"
ROW_TYPE = PresenceStreamRow ROW_TYPE = PresenceStreamRow
@ -302,7 +296,7 @@ class PresenceFederationStream(Stream):
send. send.
""" """
@attr.s(slots=True, auto_attribs=True) @attr.s(slots=True, frozen=True, auto_attribs=True)
class PresenceFederationStreamRow: class PresenceFederationStreamRow:
destination: str destination: str
user_id: str user_id: str
@ -320,9 +314,10 @@ class PresenceFederationStream(Stream):
class TypingStream(Stream): class TypingStream(Stream):
TypingStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"TypingStreamRow", ("room_id", "user_ids") # str # list(str) class TypingStreamRow:
) room_id: str
user_ids: List[str]
NAME = "typing" NAME = "typing"
ROW_TYPE = TypingStreamRow ROW_TYPE = TypingStreamRow
@ -348,16 +343,13 @@ class TypingStream(Stream):
class ReceiptsStream(Stream): class ReceiptsStream(Stream):
ReceiptsStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"ReceiptsStreamRow", class ReceiptsStreamRow:
( room_id: str
"room_id", # str receipt_type: str
"receipt_type", # str user_id: str
"user_id", # str event_id: str
"event_id", # str data: dict
"data", # dict
),
)
NAME = "receipts" NAME = "receipts"
ROW_TYPE = ReceiptsStreamRow ROW_TYPE = ReceiptsStreamRow
@ -374,7 +366,9 @@ class ReceiptsStream(Stream):
class PushRulesStream(Stream): class PushRulesStream(Stream):
"""A user has changed their push rules""" """A user has changed their push rules"""
PushRulesStreamRow = namedtuple("PushRulesStreamRow", ("user_id",)) # str @attr.s(slots=True, frozen=True, auto_attribs=True)
class PushRulesStreamRow:
user_id: str
NAME = "push_rules" NAME = "push_rules"
ROW_TYPE = PushRulesStreamRow ROW_TYPE = PushRulesStreamRow
@ -396,10 +390,12 @@ class PushRulesStream(Stream):
class PushersStream(Stream): class PushersStream(Stream):
"""A user has added/changed/removed a pusher""" """A user has added/changed/removed a pusher"""
PushersStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"PushersStreamRow", class PushersStreamRow:
("user_id", "app_id", "pushkey", "deleted"), # str # str # str # bool user_id: str
) app_id: str
pushkey: str
deleted: bool
NAME = "pushers" NAME = "pushers"
ROW_TYPE = PushersStreamRow ROW_TYPE = PushersStreamRow
@ -419,7 +415,7 @@ class CachesStream(Stream):
the cache on the workers the cache on the workers
""" """
@attr.s(slots=True) @attr.s(slots=True, frozen=True, auto_attribs=True)
class CachesStreamRow: class CachesStreamRow:
"""Stream to inform workers they should invalidate their cache. """Stream to inform workers they should invalidate their cache.
@ -430,9 +426,9 @@ class CachesStream(Stream):
invalidation_ts: Timestamp of when the invalidation took place. invalidation_ts: Timestamp of when the invalidation took place.
""" """
cache_func = attr.ib(type=str) cache_func: str
keys = attr.ib(type=Optional[List[Any]]) keys: Optional[List[Any]]
invalidation_ts = attr.ib(type=int) invalidation_ts: int
NAME = "caches" NAME = "caches"
ROW_TYPE = CachesStreamRow ROW_TYPE = CachesStreamRow
@ -451,9 +447,9 @@ class DeviceListsStream(Stream):
told about a device update. told about a device update.
""" """
@attr.s(slots=True) @attr.s(slots=True, frozen=True, auto_attribs=True)
class DeviceListsStreamRow: class DeviceListsStreamRow:
entity = attr.ib(type=str) entity: str
NAME = "device_lists" NAME = "device_lists"
ROW_TYPE = DeviceListsStreamRow ROW_TYPE = DeviceListsStreamRow
@ -470,7 +466,9 @@ class DeviceListsStream(Stream):
class ToDeviceStream(Stream): class ToDeviceStream(Stream):
"""New to_device messages for a client""" """New to_device messages for a client"""
ToDeviceStreamRow = namedtuple("ToDeviceStreamRow", ("entity",)) # str @attr.s(slots=True, frozen=True, auto_attribs=True)
class ToDeviceStreamRow:
entity: str
NAME = "to_device" NAME = "to_device"
ROW_TYPE = ToDeviceStreamRow ROW_TYPE = ToDeviceStreamRow
@ -487,9 +485,11 @@ class ToDeviceStream(Stream):
class TagAccountDataStream(Stream): class TagAccountDataStream(Stream):
"""Someone added/removed a tag for a room""" """Someone added/removed a tag for a room"""
TagAccountDataStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"TagAccountDataStreamRow", ("user_id", "room_id", "data") # str # str # dict class TagAccountDataStreamRow:
) user_id: str
room_id: str
data: JsonDict
NAME = "tag_account_data" NAME = "tag_account_data"
ROW_TYPE = TagAccountDataStreamRow ROW_TYPE = TagAccountDataStreamRow
@ -506,10 +506,11 @@ class TagAccountDataStream(Stream):
class AccountDataStream(Stream): class AccountDataStream(Stream):
"""Global or per room account data was changed""" """Global or per room account data was changed"""
AccountDataStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"AccountDataStreamRow", class AccountDataStreamRow:
("user_id", "room_id", "data_type"), # str # Optional[str] # str user_id: str
) room_id: Optional[str]
data_type: str
NAME = "account_data" NAME = "account_data"
ROW_TYPE = AccountDataStreamRow ROW_TYPE = AccountDataStreamRow
@ -573,10 +574,12 @@ class AccountDataStream(Stream):
class GroupServerStream(Stream): class GroupServerStream(Stream):
GroupsStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"GroupsStreamRow", class GroupsStreamRow:
("group_id", "user_id", "type", "content"), # str # str # str # dict group_id: str
) user_id: str
type: str
content: JsonDict
NAME = "groups" NAME = "groups"
ROW_TYPE = GroupsStreamRow ROW_TYPE = GroupsStreamRow
@ -593,7 +596,9 @@ class GroupServerStream(Stream):
class UserSignatureStream(Stream): class UserSignatureStream(Stream):
"""A user has signed their own device with their user-signing key""" """A user has signed their own device with their user-signing key"""
UserSignatureStreamRow = namedtuple("UserSignatureStreamRow", ("user_id")) # str @attr.s(slots=True, frozen=True, auto_attribs=True)
class UserSignatureStreamRow:
user_id: str
NAME = "user_signature" NAME = "user_signature"
ROW_TYPE = UserSignatureStreamRow ROW_TYPE = UserSignatureStreamRow

View file

@ -12,14 +12,16 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from collections import namedtuple
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Tuple from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Tuple
import attr
from synapse.replication.tcp.streams._base import ( from synapse.replication.tcp.streams._base import (
Stream, Stream,
current_token_without_instance, current_token_without_instance,
make_http_update_function, make_http_update_function,
) )
from synapse.types import JsonDict
if TYPE_CHECKING: if TYPE_CHECKING:
from synapse.server import HomeServer from synapse.server import HomeServer
@ -30,13 +32,10 @@ class FederationStream(Stream):
sending disabled. sending disabled.
""" """
FederationStreamRow = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"FederationStreamRow", class FederationStreamRow:
( type: str # the type of data as defined in the BaseFederationRows
"type", # str, the type of data as defined in the BaseFederationRows data: JsonDict # serialization of a federation.send_queue.BaseFederationRow
"data", # dict, serialization of a federation.send_queue.BaseFederationRow
),
)
NAME = "federation" NAME = "federation"
ROW_TYPE = FederationStreamRow ROW_TYPE = FederationStreamRow

View file

@ -739,14 +739,21 @@ class MediaRepository:
# We deduplicate the thumbnail sizes by ignoring the cropped versions if # We deduplicate the thumbnail sizes by ignoring the cropped versions if
# they have the same dimensions of a scaled one. # they have the same dimensions of a scaled one.
thumbnails: Dict[Tuple[int, int, str], str] = {} thumbnails: Dict[Tuple[int, int, str], str] = {}
for r_width, r_height, r_method, r_type in requirements: for requirement in requirements:
if r_method == "crop": if requirement.method == "crop":
thumbnails.setdefault((r_width, r_height, r_type), r_method) thumbnails.setdefault(
elif r_method == "scale": (requirement.width, requirement.height, requirement.media_type),
t_width, t_height = thumbnailer.aspect(r_width, r_height) requirement.method,
)
elif requirement.method == "scale":
t_width, t_height = thumbnailer.aspect(
requirement.width, requirement.height
)
t_width = min(m_width, t_width) t_width = min(m_width, t_width)
t_height = min(m_height, t_height) t_height = min(m_height, t_height)
thumbnails[(t_width, t_height, r_type)] = r_method thumbnails[
(t_width, t_height, requirement.media_type)
] = requirement.method
# Now we generate the thumbnails for each dimension, store it # Now we generate the thumbnails for each dimension, store it
for (t_width, t_height, t_type), t_method in thumbnails.items(): for (t_width, t_height, t_type), t_method in thumbnails.items():

View file

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
import heapq import heapq
import logging import logging
from collections import defaultdict, namedtuple from collections import defaultdict
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
@ -69,9 +69,6 @@ state_groups_histogram = Histogram(
) )
KeyStateTuple = namedtuple("KeyStateTuple", ("context", "type", "state_key"))
EVICTION_TIMEOUT_SECONDS = 60 * 60 EVICTION_TIMEOUT_SECONDS = 60 * 60

View file

@ -12,16 +12,22 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from collections import namedtuple
from typing import Iterable, List, Optional, Tuple from typing import Iterable, List, Optional, Tuple
import attr
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
from synapse.storage.database import LoggingTransaction from synapse.storage.database import LoggingTransaction
from synapse.storage.databases.main import CacheInvalidationWorkerStore from synapse.storage.databases.main import CacheInvalidationWorkerStore
from synapse.types import RoomAlias from synapse.types import RoomAlias
from synapse.util.caches.descriptors import cached from synapse.util.caches.descriptors import cached
RoomAliasMapping = namedtuple("RoomAliasMapping", ("room_id", "room_alias", "servers"))
@attr.s(slots=True, frozen=True, auto_attribs=True)
class RoomAliasMapping:
room_id: str
room_alias: str
servers: List[str]
class DirectoryWorkerStore(CacheInvalidationWorkerStore): class DirectoryWorkerStore(CacheInvalidationWorkerStore):

View file

@ -1976,14 +1976,17 @@ class PersistEventsStore:
txn, self.store.get_retention_policy_for_room, (event.room_id,) txn, self.store.get_retention_policy_for_room, (event.room_id,)
) )
def store_event_search_txn(self, txn, event, key, value): def store_event_search_txn(
self, txn: LoggingTransaction, event: EventBase, key: str, value: str
) -> None:
"""Add event to the search table """Add event to the search table
Args: Args:
txn (cursor): txn: The database transaction.
event (EventBase): event: The event being added to the search table.
key (str): key: A key describing the search value (one of "content.name",
value (str): "content.topic", or "content.body")
value: The value from the event's content.
""" """
self.store.store_search_entries_txn( self.store.store_search_entries_txn(
txn, txn,

View file

@ -13,11 +13,22 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import collections
import logging import logging
from abc import abstractmethod from abc import abstractmethod
from enum import Enum from enum import Enum
from typing import TYPE_CHECKING, Any, Awaitable, Dict, List, Optional, Tuple, cast from typing import (
TYPE_CHECKING,
Any,
Awaitable,
Dict,
List,
Optional,
Tuple,
Union,
cast,
)
import attr
from synapse.api.constants import EventContentFields, EventTypes, JoinRules from synapse.api.constants import EventContentFields, EventTypes, JoinRules
from synapse.api.errors import StoreError from synapse.api.errors import StoreError
@ -43,9 +54,10 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
RatelimitOverride = collections.namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"RatelimitOverride", ("messages_per_second", "burst_count") class RatelimitOverride:
) messages_per_second: int
burst_count: int
class RoomSortOrder(Enum): class RoomSortOrder(Enum):
@ -207,6 +219,7 @@ class RoomWorkerStore(CacheInvalidationWorkerStore):
WHERE appservice_id = ? AND network_id = ? WHERE appservice_id = ? AND network_id = ?
""" """
query_args.append(network_tuple.appservice_id) query_args.append(network_tuple.appservice_id)
assert network_tuple.network_id is not None
query_args.append(network_tuple.network_id) query_args.append(network_tuple.network_id)
else: else:
published_sql = """ published_sql = """
@ -284,7 +297,7 @@ class RoomWorkerStore(CacheInvalidationWorkerStore):
""" """
where_clauses = [] where_clauses = []
query_args = [] query_args: List[Union[str, int]] = []
if network_tuple: if network_tuple:
if network_tuple.appservice_id: if network_tuple.appservice_id:
@ -293,6 +306,7 @@ class RoomWorkerStore(CacheInvalidationWorkerStore):
WHERE appservice_id = ? AND network_id = ? WHERE appservice_id = ? AND network_id = ?
""" """
query_args.append(network_tuple.appservice_id) query_args.append(network_tuple.appservice_id)
assert network_tuple.network_id is not None
query_args.append(network_tuple.network_id) query_args.append(network_tuple.network_id)
else: else:
published_sql = """ published_sql = """

View file

@ -14,9 +14,10 @@
import logging import logging
import re import re
from collections import namedtuple
from typing import TYPE_CHECKING, Collection, Iterable, List, Optional, Set from typing import TYPE_CHECKING, Collection, Iterable, List, Optional, Set
import attr
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
from synapse.events import EventBase from synapse.events import EventBase
from synapse.storage._base import SQLBaseStore, db_to_json, make_in_list_sql_clause from synapse.storage._base import SQLBaseStore, db_to_json, make_in_list_sql_clause
@ -33,10 +34,15 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
SearchEntry = namedtuple(
"SearchEntry", @attr.s(slots=True, frozen=True, auto_attribs=True)
["key", "value", "event_id", "room_id", "stream_ordering", "origin_server_ts"], class SearchEntry:
) key: str
value: str
event_id: str
room_id: str
stream_ordering: Optional[int]
origin_server_ts: int
def _clean_value_for_search(value: str) -> str: def _clean_value_for_search(value: str) -> str:

View file

@ -14,7 +14,6 @@
# limitations under the License. # limitations under the License.
import collections.abc import collections.abc
import logging import logging
from collections import namedtuple
from typing import TYPE_CHECKING, Iterable, Optional, Set from typing import TYPE_CHECKING, Iterable, Optional, Set
from synapse.api.constants import EventTypes, Membership from synapse.api.constants import EventTypes, Membership
@ -43,19 +42,6 @@ logger = logging.getLogger(__name__)
MAX_STATE_DELTA_HOPS = 100 MAX_STATE_DELTA_HOPS = 100
class _GetStateGroupDelta(
namedtuple("_GetStateGroupDelta", ("prev_group", "delta_ids"))
):
"""Return type of get_state_group_delta that implements __len__, which lets
us use the itrable flag when caching
"""
__slots__ = []
def __len__(self):
return len(self.delta_ids) if self.delta_ids else 0
# this inherits from EventsWorkerStore because it calls self.get_events # this inherits from EventsWorkerStore because it calls self.get_events
class StateGroupWorkerStore(EventsWorkerStore, SQLBaseStore): class StateGroupWorkerStore(EventsWorkerStore, SQLBaseStore):
"""The parts of StateGroupStore that can be called from workers.""" """The parts of StateGroupStore that can be called from workers."""

View file

@ -36,9 +36,9 @@ what sort order was used:
""" """
import abc import abc
import logging import logging
from collections import namedtuple
from typing import TYPE_CHECKING, Collection, Dict, List, Optional, Set, Tuple from typing import TYPE_CHECKING, Collection, Dict, List, Optional, Set, Tuple
import attr
from frozendict import frozendict from frozendict import frozendict
from twisted.internet import defer from twisted.internet import defer
@ -74,9 +74,11 @@ _TOPOLOGICAL_TOKEN = "topological"
# Used as return values for pagination APIs # Used as return values for pagination APIs
_EventDictReturn = namedtuple( @attr.s(slots=True, frozen=True, auto_attribs=True)
"_EventDictReturn", ("event_id", "topological_ordering", "stream_ordering") class _EventDictReturn:
) event_id: str
topological_ordering: Optional[int]
stream_ordering: int
def generate_pagination_where_clause( def generate_pagination_where_clause(
@ -825,7 +827,7 @@ class StreamWorkerStore(EventsWorkerStore, SQLBaseStore, metaclass=abc.ABCMeta):
for event, row in zip(events, rows): for event, row in zip(events, rows):
stream = row.stream_ordering stream = row.stream_ordering
if topo_order and row.topological_ordering: if topo_order and row.topological_ordering:
topo = row.topological_ordering topo: Optional[int] = row.topological_ordering
else: else:
topo = None topo = None
internal = event.internal_metadata internal = event.internal_metadata

View file

@ -15,7 +15,6 @@
import abc import abc
import re import re
import string import string
from collections import namedtuple
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
@ -227,8 +226,7 @@ class DomainSpecificString(metaclass=abc.ABCMeta):
localpart = attr.ib(type=str) localpart = attr.ib(type=str)
domain = attr.ib(type=str) domain = attr.ib(type=str)
# Because this class is a namedtuple of strings and booleans, it is deeply # Because this is a frozen class, it is deeply immutable.
# immutable.
def __copy__(self): def __copy__(self):
return self return self
@ -708,16 +706,18 @@ class PersistedEventPosition:
return RoomStreamToken(None, self.stream) return RoomStreamToken(None, self.stream)
class ThirdPartyInstanceID( @attr.s(slots=True, frozen=True, auto_attribs=True)
namedtuple("ThirdPartyInstanceID", ("appservice_id", "network_id")) class ThirdPartyInstanceID:
): appservice_id: Optional[str]
network_id: Optional[str]
# Deny iteration because it will bite you if you try to create a singleton # Deny iteration because it will bite you if you try to create a singleton
# set by: # set by:
# users = set(user) # users = set(user)
def __iter__(self): def __iter__(self):
raise ValueError("Attempted to iterate a %s" % (type(self).__name__,)) raise ValueError("Attempted to iterate a %s" % (type(self).__name__,))
# Because this class is a namedtuple of strings, it is deeply immutable. # Because this class is a frozen class, it is deeply immutable.
def __copy__(self): def __copy__(self):
return self return self
@ -725,22 +725,18 @@ class ThirdPartyInstanceID(
return self return self
@classmethod @classmethod
def from_string(cls, s): def from_string(cls, s: str) -> "ThirdPartyInstanceID":
bits = s.split("|", 2) bits = s.split("|", 2)
if len(bits) != 2: if len(bits) != 2:
raise SynapseError(400, "Invalid ID %r" % (s,)) raise SynapseError(400, "Invalid ID %r" % (s,))
return cls(appservice_id=bits[0], network_id=bits[1]) return cls(appservice_id=bits[0], network_id=bits[1])
def to_string(self): def to_string(self) -> str:
return "%s|%s" % (self.appservice_id, self.network_id) return "%s|%s" % (self.appservice_id, self.network_id)
__str__ = to_string __str__ = to_string
@classmethod
def create(cls, appservice_id, network_id):
return cls(appservice_id=appservice_id, network_id=network_id)
@attr.s(slots=True) @attr.s(slots=True)
class ReadReceipt: class ReadReceipt:

View file

@ -62,7 +62,11 @@ class FederationAckTestCase(HomeserverTestCase):
"federation", "federation",
"master", "master",
token=10, token=10,
rows=[FederationStream.FederationStreamRow(type="x", data=[1, 2, 3])], rows=[
FederationStream.FederationStreamRow(
type="x", data={"test": [1, 2, 3]}
)
],
) )
) )