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

Commit

Permalink
Remove various bits of compatibility code for Python <3.6 (#9879)
Browse files Browse the repository at this point in the history
I went through and removed a bunch of cruft that was lying around for compatibility with old Python versions. This PR also will now prevent Synapse from starting unless you're running Python 3.6+.
  • Loading branch information
anoadragon453 authored Apr 27, 2021
1 parent 1350b05 commit fe604a0
Show file tree
Hide file tree
Showing 16 changed files with 29 additions and 98 deletions.
1 change: 1 addition & 0 deletions changelog.d/9879.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove backwards-compatibility code for Python versions < 3.6.
1 change: 0 additions & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ files =
synapse/push,
synapse/replication,
synapse/rest,
synapse/secrets.py,
synapse/server.py,
synapse/server_notices,
synapse/spam_checker_api,
Expand Down
4 changes: 2 additions & 2 deletions synapse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
import sys

# Check that we're not running on an unsupported Python version.
if sys.version_info < (3, 5):
print("Synapse requires Python 3.5 or above.")
if sys.version_info < (3, 6):
print("Synapse requires Python 3.6 or above.")
sys.exit(1)

# Twisted and canonicaljson will fail to import when this file is executed to
Expand Down
9 changes: 2 additions & 7 deletions synapse/python_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"typing-extensions>=3.7.4",
# We enforce that we have a `cryptography` version that bundles an `openssl`
# with the latest security patches.
"cryptography>=3.4.7;python_version>='3.6'",
"cryptography>=3.4.7",
]

CONDITIONAL_REQUIREMENTS = {
Expand All @@ -100,14 +100,9 @@
# that use the protocol, such as Let's Encrypt.
"acme": [
"txacme>=0.9.2",
# txacme depends on eliot. Eliot 1.8.0 is incompatible with
# python 3.5.2, as per https://github.com/itamarst/eliot/issues/418
"eliot<1.8.0;python_version<'3.5.3'",
],
"saml2": [
# pysaml2 6.4.0 is incompatible with Python 3.5 (see https://github.com/IdentityPython/pysaml2/issues/749)
"pysaml2>=4.5.0,<6.4.0;python_version<'3.6'",
"pysaml2>=4.5.0;python_version>='3.6'",
"pysaml2>=4.5.0",
],
"oidc": ["authlib>=0.14.0"],
# systemd-python is necessary for logging to the systemd journal via
Expand Down
3 changes: 2 additions & 1 deletion synapse/rest/admin/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import hashlib
import hmac
import logging
import secrets
from http import HTTPStatus
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple

Expand Down Expand Up @@ -375,7 +376,7 @@ def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
"""
self._clear_old_nonces()

nonce = self.hs.get_secrets().token_hex(64)
nonce = secrets.token_hex(64)
self.nonces[nonce] = int(self.reactor.seconds())
return 200, {"nonce": nonce}

Expand Down
10 changes: 1 addition & 9 deletions synapse/rest/consent/consent_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,6 @@

logger = logging.getLogger(__name__)

# use hmac.compare_digest if we have it (python 2.7.7), else just use equality
if hasattr(hmac, "compare_digest"):
compare_digest = hmac.compare_digest
else:

def compare_digest(a, b):
return a == b


class ConsentResource(DirectServeHtmlResource):
"""A twisted Resource to display a privacy policy and gather consent to it
Expand Down Expand Up @@ -209,5 +201,5 @@ def _check_hash(self, userid, userhmac):
.encode("ascii")
)

if not compare_digest(want_mac, userhmac):
if not hmac.compare_digest(want_mac, userhmac):
raise SynapseError(HTTPStatus.FORBIDDEN, "HMAC incorrect")
2 changes: 1 addition & 1 deletion synapse/rest/media/v1/filepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
NEW_FORMAT_ID_RE = re.compile(r"^\d\d\d\d-\d\d-\d\d")


def _wrap_in_base_path(func: "Callable[..., str]") -> "Callable[..., str]":
def _wrap_in_base_path(func: Callable[..., str]) -> Callable[..., str]:
"""Takes a function that returns a relative path and turns it into an
absolute path based on the location of the primary media store
"""
Expand Down
44 changes: 0 additions & 44 deletions synapse/secrets.py

This file was deleted.

5 changes: 0 additions & 5 deletions synapse/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@
MediaRepository,
MediaRepositoryResource,
)
from synapse.secrets import Secrets
from synapse.server_notices.server_notices_manager import ServerNoticesManager
from synapse.server_notices.server_notices_sender import ServerNoticesSender
from synapse.server_notices.worker_server_notices_sender import (
Expand Down Expand Up @@ -641,10 +640,6 @@ def get_groups_attestation_signing(self) -> GroupAttestationSigning:
def get_groups_attestation_renewer(self) -> GroupAttestionRenewer:
return GroupAttestionRenewer(self)

@cache_in_self
def get_secrets(self) -> Secrets:
return Secrets()

@cache_in_self
def get_stats_handler(self) -> StatsHandler:
return StatsHandler(self)
Expand Down
2 changes: 1 addition & 1 deletion synapse/storage/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def db_to_json(db_content: Union[memoryview, bytes, bytearray, str]) -> Any:
db_content = db_content.tobytes()

# Decode it to a Unicode string before feeding it to the JSON decoder, since
# Python 3.5 does not support deserializing bytes.
# it only supports handling strings
if isinstance(db_content, (bytes, bytearray)):
db_content = db_content.decode("utf8")

Expand Down
15 changes: 6 additions & 9 deletions synapse/storage/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,7 @@ def __getattr__(self, name):


# The type of entry which goes on our after_callbacks and exception_callbacks lists.
#
# Python 3.5.2 doesn't support Callable with an ellipsis, so we wrap it in quotes so
# that mypy sees the type but the runtime python doesn't.
_CallbackListEntry = Tuple["Callable[..., None]", Iterable[Any], Dict[str, Any]]
_CallbackListEntry = Tuple[Callable[..., None], Iterable[Any], Dict[str, Any]]


R = TypeVar("R")
Expand Down Expand Up @@ -221,7 +218,7 @@ def __init__(
self.after_callbacks = after_callbacks
self.exception_callbacks = exception_callbacks

def call_after(self, callback: "Callable[..., None]", *args: Any, **kwargs: Any):
def call_after(self, callback: Callable[..., None], *args: Any, **kwargs: Any):
"""Call the given callback on the main twisted thread after the
transaction has finished. Used to invalidate the caches on the
correct thread.
Expand All @@ -233,7 +230,7 @@ def call_after(self, callback: "Callable[..., None]", *args: Any, **kwargs: Any)
self.after_callbacks.append((callback, args, kwargs))

def call_on_exception(
self, callback: "Callable[..., None]", *args: Any, **kwargs: Any
self, callback: Callable[..., None], *args: Any, **kwargs: Any
):
# if self.exception_callbacks is None, that means that whatever constructed the
# LoggingTransaction isn't expecting there to be any callbacks; assert that
Expand Down Expand Up @@ -485,7 +482,7 @@ def new_transaction(
desc: str,
after_callbacks: List[_CallbackListEntry],
exception_callbacks: List[_CallbackListEntry],
func: "Callable[..., R]",
func: Callable[..., R],
*args: Any,
**kwargs: Any,
) -> R:
Expand Down Expand Up @@ -618,7 +615,7 @@ def new_transaction(
async def runInteraction(
self,
desc: str,
func: "Callable[..., R]",
func: Callable[..., R],
*args: Any,
db_autocommit: bool = False,
**kwargs: Any,
Expand Down Expand Up @@ -678,7 +675,7 @@ async def runInteraction(

async def runWithConnection(
self,
func: "Callable[..., R]",
func: Callable[..., R],
*args: Any,
db_autocommit: bool = False,
**kwargs: Any,
Expand Down
2 changes: 1 addition & 1 deletion synapse/util/caches/response_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def remove(r):
return result.observe()

def wrap(
self, key: T, callback: "Callable[..., Any]", *args: Any, **kwargs: Any
self, key: T, callback: Callable[..., Any], *args: Any, **kwargs: Any
) -> defer.Deferred:
"""Wrap together a *get* and *set* call, taking care of logcontexts
Expand Down
15 changes: 6 additions & 9 deletions tests/rest/admin/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import urllib.parse
from binascii import unhexlify
from typing import List, Optional
from unittest.mock import Mock
from unittest.mock import Mock, patch

import synapse.rest.admin
from synapse.api.constants import UserTypes
Expand Down Expand Up @@ -54,8 +54,6 @@ def make_homeserver(self, reactor, clock):
self.datastore = Mock(return_value=Mock())
self.datastore.get_current_state_deltas = Mock(return_value=(0, []))

self.secrets = Mock()

self.hs = self.setup_test_homeserver()

self.hs.config.registration_shared_secret = "shared"
Expand Down Expand Up @@ -84,14 +82,13 @@ def test_get_nonce(self):
Calling GET on the endpoint will return a randomised nonce, using the
homeserver's secrets provider.
"""
secrets = Mock()
secrets.token_hex = Mock(return_value="abcd")

self.hs.get_secrets = Mock(return_value=secrets)
with patch("secrets.token_hex") as token_hex:
# Patch secrets.token_hex for the duration of this context
token_hex.return_value = "abcd"

channel = self.make_request("GET", self.url)
channel = self.make_request("GET", self.url)

self.assertEqual(channel.json_body, {"nonce": "abcd"})
self.assertEqual(channel.json_body, {"nonce": "abcd"})

def test_expired_nonce(self):
"""
Expand Down
3 changes: 2 additions & 1 deletion tests/storage/test__base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import secrets

from tests import unittest

Expand All @@ -21,7 +22,7 @@ class UpsertManyTests(unittest.HomeserverTestCase):
def prepare(self, reactor, clock, hs):
self.storage = hs.get_datastore()

self.table_name = "table_" + hs.get_secrets().token_hex(6)
self.table_name = "table_" + secrets.token_hex(6)
self.get_success(
self.storage.db_pool.runInteraction(
"create",
Expand Down
2 changes: 1 addition & 1 deletion tests/unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import hmac
import inspect
import logging
import secrets
import time
from typing import Callable, Dict, Iterable, Optional, Tuple, Type, TypeVar, Union
from unittest.mock import Mock, patch
Expand Down Expand Up @@ -626,7 +627,6 @@ def create_and_send_event(
str: The new event's ID.
"""
event_creator = self.hs.get_event_creation_handler()
secrets = self.hs.get_secrets()
requester = create_requester(user)

event, context = self.get_success(
Expand Down
9 changes: 3 additions & 6 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ deps =
# installed on that).
#
# anyway, make sure that we have a recent enough setuptools.
setuptools>=18.5 ; python_version >= '3.6'
setuptools>=18.5,<51.0.0 ; python_version < '3.6'
setuptools>=18.5

# we also need a semi-recent version of pip, because old ones fail to
# install the "enum34" dependency of cryptography.
pip>=10 ; python_version >= '3.6'
pip>=10,<21.0 ; python_version < '3.6'
pip>=10

# directories/files we run the linters on.
# if you update this list, make sure to do the same in scripts-dev/lint.sh
Expand Down Expand Up @@ -168,8 +166,7 @@ skip_install = true
usedevelop = false
deps =
coverage
pip>=10 ; python_version >= '3.6'
pip>=10,<21.0 ; python_version < '3.6'
pip>=10
commands=
coverage combine
coverage report
Expand Down

0 comments on commit fe604a0

Please sign in to comment.