Просмотр исходного кода

Remove various bits of compatibility code for Python <3.6 (#9879)

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+.
tags/v1.33.0rc1
Andrew Morgan 3 лет назад
committed by GitHub
Родитель
Сommit
fe604a022a
Не найден GPG ключ соответствующий данной подписи Идентификатор GPG ключа: 4AEE18F83AFDEB23
16 измененных файлов: 29 добавлений и 98 удалений
  1. +1
    -0
      changelog.d/9879.misc
  2. +0
    -1
      mypy.ini
  3. +2
    -2
      synapse/__init__.py
  4. +2
    -7
      synapse/python_dependencies.py
  5. +2
    -1
      synapse/rest/admin/users.py
  6. +1
    -9
      synapse/rest/consent/consent_resource.py
  7. +1
    -1
      synapse/rest/media/v1/filepath.py
  8. +0
    -44
      synapse/secrets.py
  9. +0
    -5
      synapse/server.py
  10. +1
    -1
      synapse/storage/_base.py
  11. +6
    -9
      synapse/storage/database.py
  12. +1
    -1
      synapse/util/caches/response_cache.py
  13. +6
    -9
      tests/rest/admin/test_user.py
  14. +2
    -1
      tests/storage/test__base.py
  15. +1
    -1
      tests/unittest.py
  16. +3
    -6
      tox.ini

+ 1
- 0
changelog.d/9879.misc Просмотреть файл

@@ -0,0 +1 @@
Remove backwards-compatibility code for Python versions < 3.6.

+ 0
- 1
mypy.ini Просмотреть файл

@@ -41,7 +41,6 @@ files =
synapse/push,
synapse/replication,
synapse/rest,
synapse/secrets.py,
synapse/server.py,
synapse/server_notices,
synapse/spam_checker_api,


+ 2
- 2
synapse/__init__.py Просмотреть файл

@@ -21,8 +21,8 @@ import os
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


+ 2
- 7
synapse/python_dependencies.py Просмотреть файл

@@ -85,7 +85,7 @@ REQUIREMENTS = [
"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 = {
@@ -100,14 +100,9 @@ CONDITIONAL_REQUIREMENTS = {
# 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


+ 2
- 1
synapse/rest/admin/users.py Просмотреть файл

@@ -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

@@ -375,7 +376,7 @@ class UserRegisterServlet(RestServlet):
"""
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}



+ 1
- 9
synapse/rest/consent/consent_resource.py Просмотреть файл

@@ -32,14 +32,6 @@ TEMPLATE_LANGUAGE = "en"

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
@@ -209,5 +201,5 @@ class ConsentResource(DirectServeHtmlResource):
.encode("ascii")
)

if not compare_digest(want_mac, userhmac):
if not hmac.compare_digest(want_mac, userhmac):
raise SynapseError(HTTPStatus.FORBIDDEN, "HMAC incorrect")

+ 1
- 1
synapse/rest/media/v1/filepath.py Просмотреть файл

@@ -21,7 +21,7 @@ from typing import Callable, List
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
"""


+ 0
- 44
synapse/secrets.py Просмотреть файл

@@ -1,44 +0,0 @@
# Copyright 2018 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Injectable secrets module for Synapse.

See https://docs.python.org/3/library/secrets.html#module-secrets for the API
used in Python 3.6, and the API emulated in Python 2.7.
"""
import sys

# secrets is available since python 3.6
if sys.version_info[0:2] >= (3, 6):
import secrets

class Secrets:
def token_bytes(self, nbytes: int = 32) -> bytes:
return secrets.token_bytes(nbytes)

def token_hex(self, nbytes: int = 32) -> str:
return secrets.token_hex(nbytes)


else:
import binascii
import os

class Secrets:
def token_bytes(self, nbytes: int = 32) -> bytes:
return os.urandom(nbytes)

def token_hex(self, nbytes: int = 32) -> str:
return binascii.hexlify(self.token_bytes(nbytes)).decode("ascii")

+ 0
- 5
synapse/server.py Просмотреть файл

@@ -126,7 +126,6 @@ from synapse.rest.media.v1.media_repository import (
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 (
@@ -641,10 +640,6 @@ class HomeServer(metaclass=abc.ABCMeta):
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)


+ 1
- 1
synapse/storage/_base.py Просмотреть файл

@@ -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")



+ 6
- 9
synapse/storage/database.py Просмотреть файл

@@ -171,10 +171,7 @@ class LoggingDatabaseConnection:


# 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")
@@ -221,7 +218,7 @@ class LoggingTransaction:
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.
@@ -233,7 +230,7 @@ class LoggingTransaction:
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
@@ -485,7 +482,7 @@ class DatabasePool:
desc: str,
after_callbacks: List[_CallbackListEntry],
exception_callbacks: List[_CallbackListEntry],
func: "Callable[..., R]",
func: Callable[..., R],
*args: Any,
**kwargs: Any,
) -> R:
@@ -618,7 +615,7 @@ class DatabasePool:
async def runInteraction(
self,
desc: str,
func: "Callable[..., R]",
func: Callable[..., R],
*args: Any,
db_autocommit: bool = False,
**kwargs: Any,
@@ -678,7 +675,7 @@ class DatabasePool:

async def runWithConnection(
self,
func: "Callable[..., R]",
func: Callable[..., R],
*args: Any,
db_autocommit: bool = False,
**kwargs: Any,


+ 1
- 1
synapse/util/caches/response_cache.py Просмотреть файл

@@ -110,7 +110,7 @@ class ResponseCache(Generic[T]):
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



+ 6
- 9
tests/rest/admin/test_user.py Просмотреть файл

@@ -18,7 +18,7 @@ import json
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
@@ -54,8 +54,6 @@ class UserRegisterTestCase(unittest.HomeserverTestCase):
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"
@@ -84,14 +82,13 @@ class UserRegisterTestCase(unittest.HomeserverTestCase):
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):
"""


+ 2
- 1
tests/storage/test__base.py Просмотреть файл

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import secrets

from tests import unittest

@@ -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",


+ 1
- 1
tests/unittest.py Просмотреть файл

@@ -18,6 +18,7 @@ import hashlib
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
@@ -626,7 +627,6 @@ class HomeserverTestCase(TestCase):
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(


+ 3
- 6
tox.ini Просмотреть файл

@@ -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
@@ -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


Загрузка…
Отмена
Сохранить