diff --git a/CHANGES.md b/CHANGES.md
index 206859cff7..a41abbefba 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,12 @@
+Synapse 1.33.1 (2021-05-06)
+===========================
+
+Bugfixes
+--------
+
+- Fix bug where `/sync` would break if using the latest version of `attrs` dependency, by pinning to a previous version. ([\#9937](https://github.com/matrix-org/synapse/issues/9937))
+
+
Synapse 1.33.0 (2021-05-05)
===========================
diff --git a/changelog.d/9919.feature b/changelog.d/9919.feature
deleted file mode 100644
index 07747505d2..0000000000
--- a/changelog.d/9919.feature
+++ /dev/null
@@ -1 +0,0 @@
-Omit empty fields from the `/sync` response. Contributed by @deepbluev7.
diff --git a/debian/changelog b/debian/changelog
index b54d3f2bc6..de50dd14ea 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+matrix-synapse-py3 (1.33.1) stable; urgency=medium
+
+ * New synapse release 1.33.1.
+
+ -- Synapse Packaging team <packages@matrix.org> Thu, 06 May 2021 14:06:33 +0100
+
matrix-synapse-py3 (1.33.0) stable; urgency=medium
* New synapse release 1.33.0.
diff --git a/synapse/__init__.py b/synapse/__init__.py
index 5eac40730a..441cd8b339 100644
--- a/synapse/__init__.py
+++ b/synapse/__init__.py
@@ -47,7 +47,7 @@ try:
except ImportError:
pass
-__version__ = "1.33.0"
+__version__ = "1.33.1"
if bool(os.environ.get("SYNAPSE_TEST_PATCH_LOG_CONTEXTS", False)):
# We import here so that we don't have to install a bunch of deps when
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index d58eeeaa74..2113c620c6 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -78,7 +78,8 @@ REQUIREMENTS = [
# we use attr.validators.deep_iterable, which arrived in 19.1.0 (Note:
# Fedora 31 only has 19.1, so if we want to upgrade we should wait until 33
# is out in November.)
- "attrs>=19.1.0",
+ # Note: 21.1.0 broke `/sync`, see #9936
+ "attrs>=19.1.0,<21.1.0",
"netaddr>=0.7.18",
"Jinja2>=2.9",
"bleach>=1.4.3",
diff --git a/synapse/rest/client/v2_alpha/sync.py b/synapse/rest/client/v2_alpha/sync.py
index 5f85653330..95ee3f1b84 100644
--- a/synapse/rest/client/v2_alpha/sync.py
+++ b/synapse/rest/client/v2_alpha/sync.py
@@ -14,7 +14,6 @@
import itertools
import logging
-from collections import defaultdict
from typing import TYPE_CHECKING, Tuple
from synapse.api.constants import PresenceState
@@ -230,49 +229,24 @@ class SyncRestServlet(RestServlet):
)
logger.debug("building sync response dict")
-
- response: dict = defaultdict(dict)
- response["next_batch"] = await sync_result.next_batch.to_string(self.store)
-
- if sync_result.account_data:
- response["account_data"] = {"events": sync_result.account_data}
- if sync_result.presence:
- response["presence"] = SyncRestServlet.encode_presence(
- sync_result.presence, time_now
- )
-
- if sync_result.to_device:
- response["to_device"] = {"events": sync_result.to_device}
-
- if sync_result.device_lists.changed:
- response["device_lists"]["changed"] = list(sync_result.device_lists.changed)
- if sync_result.device_lists.left:
- response["device_lists"]["left"] = list(sync_result.device_lists.left)
-
- if sync_result.device_one_time_keys_count:
- response[
- "device_one_time_keys_count"
- ] = sync_result.device_one_time_keys_count
- if sync_result.device_unused_fallback_key_types:
- response[
- "org.matrix.msc2732.device_unused_fallback_key_types"
- ] = sync_result.device_unused_fallback_key_types
-
- if joined:
- response["rooms"]["join"] = joined
- if invited:
- response["rooms"]["invite"] = invited
- if archived:
- response["rooms"]["leave"] = archived
-
- if sync_result.groups.join:
- response["groups"]["join"] = sync_result.groups.join
- if sync_result.groups.invite:
- response["groups"]["invite"] = sync_result.groups.invite
- if sync_result.groups.leave:
- response["groups"]["leave"] = sync_result.groups.leave
-
- return response
+ return {
+ "account_data": {"events": sync_result.account_data},
+ "to_device": {"events": sync_result.to_device},
+ "device_lists": {
+ "changed": list(sync_result.device_lists.changed),
+ "left": list(sync_result.device_lists.left),
+ },
+ "presence": SyncRestServlet.encode_presence(sync_result.presence, time_now),
+ "rooms": {"join": joined, "invite": invited, "leave": archived},
+ "groups": {
+ "join": sync_result.groups.join,
+ "invite": sync_result.groups.invite,
+ "leave": sync_result.groups.leave,
+ },
+ "device_one_time_keys_count": sync_result.device_one_time_keys_count,
+ "org.matrix.msc2732.device_unused_fallback_key_types": sync_result.device_unused_fallback_key_types,
+ "next_batch": await sync_result.next_batch.to_string(self.store),
+ }
@staticmethod
def encode_presence(events, time_now):
diff --git a/tests/rest/client/v2_alpha/test_sync.py b/tests/rest/client/v2_alpha/test_sync.py
index 74be5176d0..dbcbdf159a 100644
--- a/tests/rest/client/v2_alpha/test_sync.py
+++ b/tests/rest/client/v2_alpha/test_sync.py
@@ -37,7 +37,35 @@ class FilterTestCase(unittest.HomeserverTestCase):
channel = self.make_request("GET", "/sync")
self.assertEqual(channel.code, 200)
- self.assertIn("next_batch", channel.json_body)
+ self.assertTrue(
+ {
+ "next_batch",
+ "rooms",
+ "presence",
+ "account_data",
+ "to_device",
+ "device_lists",
+ }.issubset(set(channel.json_body.keys()))
+ )
+
+ def test_sync_presence_disabled(self):
+ """
+ When presence is disabled, the key does not appear in /sync.
+ """
+ self.hs.config.use_presence = False
+
+ channel = self.make_request("GET", "/sync")
+
+ self.assertEqual(channel.code, 200)
+ self.assertTrue(
+ {
+ "next_batch",
+ "rooms",
+ "account_data",
+ "to_device",
+ "device_lists",
+ }.issubset(set(channel.json_body.keys()))
+ )
class SyncFilterTestCase(unittest.HomeserverTestCase):
diff --git a/tests/server_notices/test_resource_limits_server_notices.py b/tests/server_notices/test_resource_limits_server_notices.py
index 3245aa91ca..d46521ccdc 100644
--- a/tests/server_notices/test_resource_limits_server_notices.py
+++ b/tests/server_notices/test_resource_limits_server_notices.py
@@ -306,9 +306,8 @@ class TestResourceLimitsServerNoticesWithRealRooms(unittest.HomeserverTestCase):
channel = self.make_request("GET", "/sync?timeout=0", access_token=tok)
- self.assertNotIn(
- "rooms", channel.json_body, "Got invites without server notice"
- )
+ invites = channel.json_body["rooms"]["invite"]
+ self.assertEqual(len(invites), 0, invites)
def test_invite_with_notice(self):
"""Tests that, if the MAU limit is hit, the server notices user invites each user
@@ -365,8 +364,7 @@ class TestResourceLimitsServerNoticesWithRealRooms(unittest.HomeserverTestCase):
# We could also pick another user and sync with it, which would return an
# invite to a system notices room, but it doesn't matter which user we're
# using so we use the last one because it saves us an extra sync.
- if "rooms" in channel.json_body:
- invites = channel.json_body["rooms"]["invite"]
+ invites = channel.json_body["rooms"]["invite"]
# Make sure we have an invite to process.
self.assertEqual(len(invites), 1, invites)
|