Skip to content

Commit

Permalink
Merge branch 'trunk' into 10198-mypy-test_core
Browse files Browse the repository at this point in the history
  • Loading branch information
wsanchez authored Jun 1, 2021
2 parents 233d41b + fd036b7 commit 9f0d979
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 39 deletions.
4 changes: 2 additions & 2 deletions src/twisted/conch/ssh/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ def _ssh_KEXDH_INIT(self, packet):
self.g, self.p = _kex.getDHGeneratorAndPrime(self.kexAlg)
self._startEphemeralDH()
sharedSecret = self._finishEphemeralDH(clientDHpublicKey)
h = sha1()
h = _kex.getHashProcessor(self.kexAlg)()
h.update(NS(self.otherVersionString))
h.update(NS(self.ourVersionString))
h.update(NS(self.otherKexInitPayload))
Expand Down Expand Up @@ -1857,7 +1857,7 @@ def _continueKEXDH_REPLY(self, ignored, pubKey, f, signature):
"""
serverKey = keys.Key.fromString(pubKey)
sharedSecret = self._finishEphemeralDH(f)
h = sha1()
h = _kex.getHashProcessor(self.kexAlg)()
h.update(NS(self.ourVersionString))
h.update(NS(self.otherVersionString))
h.update(NS(self.ourKexInitPayload))
Expand Down
16 changes: 11 additions & 5 deletions src/twisted/internet/asyncioreactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@


import errno
import sys

from typing import Dict, Optional, Type

Expand All @@ -24,7 +25,7 @@
from twisted.internet.abstract import FileDescriptor
from twisted.internet.interfaces import IReactorFDSet

from asyncio import get_event_loop, AbstractEventLoop, SelectorEventLoop
from asyncio import get_event_loop, AbstractEventLoop


@implementer(IReactorFDSet)
Expand All @@ -47,7 +48,7 @@ class AsyncioSelectorReactor(PosixReactorBase):
_asyncClosed = False
_log = Logger()

def __init__(self, eventloop: Optional[SelectorEventLoop] = None):
def __init__(self, eventloop: Optional[AbstractEventLoop] = None):
if eventloop is None:
_eventloop: AbstractEventLoop = get_event_loop()
else:
Expand All @@ -56,10 +57,15 @@ def __init__(self, eventloop: Optional[SelectorEventLoop] = None):
# On Python 3.8+, asyncio.get_event_loop() on
# Windows was changed to return a ProactorEventLoop
# unless the loop policy has been changed.
if not isinstance(_eventloop, SelectorEventLoop):
raise TypeError(f"SelectorEventLoop required, instead got: {_eventloop}")
if sys.platform == "win32":
from asyncio import ProactorEventLoop

self._asyncioEventloop: SelectorEventLoop = _eventloop
if isinstance(_eventloop, ProactorEventLoop):
raise TypeError(
f"ProactorEventLoop is not supported, got: {_eventloop}"
)

self._asyncioEventloop: AbstractEventLoop = _eventloop
self._writers: Dict[Type[FileDescriptor], int] = {}
self._readers: Dict[Type[FileDescriptor], int] = {}
self._continuousPolling = _ContinuousPolling(self)
Expand Down
1 change: 1 addition & 0 deletions src/twisted/newsfragments/10106.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.internet.asyncioreactor.AsyncioSelectorReactor will no longer raise a TypeError like "SelectorEventLoop required, instead got: <uvloop.Loop ...>" (broken since 21.2.0).
2 changes: 2 additions & 0 deletions src/twisted/newsfragments/10203.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
twisted.conch.ssh.transport.SSHServerTransport and twisted.conch.ssh.transport.SSHClientTransport no longer use the hardcoded
SHA1 digest for non-group key exchanges.
17 changes: 9 additions & 8 deletions src/twisted/web/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -3099,8 +3099,8 @@ class HTTPFactory(protocol.ServerFactory):
support writing to L{twisted.python.log} which, unfortunately, works
with native strings.
@ivar _reactor: An L{IReactorTime} provider used to compute logging
timestamps.
@ivar reactor: An L{IReactorTime} provider used to manage connection
timeouts and compute logging timestamps.
"""

# We need to ignore the mypy error here, because
Expand Down Expand Up @@ -3130,12 +3130,13 @@ def __init__(
the access log. L{combinedLogFormatter} when C{None} is passed.
@type logFormatter: L{IAccessLogFormatter} provider
@param reactor: A L{IReactorTime} provider used to manage connection
timeouts and compute logging timestamps.
@param reactor: An L{IReactorTime} provider used to manage connection
timeouts and compute logging timestamps. Defaults to the global
reactor.
"""
if not reactor:
from twisted.internet import reactor
self._reactor = reactor
self.reactor = reactor

if logPath is not None:
logPath = os.path.abspath(logPath)
Expand All @@ -3153,8 +3154,8 @@ def _updateLogDateTime(self):
"""
Update log datetime periodically, so we aren't always recalculating it.
"""
self._logDateTime = datetimeToLogString(self._reactor.seconds())
self._logDateTimeCall = self._reactor.callLater(1, self._updateLogDateTime)
self._logDateTime = datetimeToLogString(self.reactor.seconds())
self._logDateTimeCall = self.reactor.callLater(1, self._updateLogDateTime)

def buildProtocol(self, addr):
p = protocol.ServerFactory.buildProtocol(self, addr)
Expand All @@ -3164,7 +3165,7 @@ def buildProtocol(self, addr):
# ideally be resolved by passing the reactor more generally to the
# HTTPChannel, but that won't work for the TimeoutMixin until we fix
# https://twistedmatrix.com/trac/ticket/8488
p.callLater = self._reactor.callLater
p.callLater = self.reactor.callLater

# timeOut needs to be on the Protocol instance cause
# TimeoutMixin expects it there
Expand Down
1 change: 1 addition & 0 deletions src/twisted/web/newsfragments/10177.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Calling twisted.web.server.Site now registers its expiration timeout using the reactor associated with its twisted.web.server.Site. Site now a reactor attribute via its superclass, twisted.web.http.HTTPFactory.
41 changes: 33 additions & 8 deletions src/twisted/web/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,12 +686,23 @@ class Session(components.Componentized):
This utility class contains no functionality, but is used to
represent a session.
@ivar site: The L{Site} that generated the session.
@type site: L{Site}
@ivar uid: A unique identifier for the session.
@type uid: L{bytes}
@ivar _reactor: An object providing L{IReactorTime} to use for scheduling
expiration.
@ivar sessionTimeout: timeout of a session, in seconds.
@ivar sessionTimeout: Time after last modification the session will expire,
in seconds.
@type sessionTimeout: L{float}
@ivar lastModified: Time the C{touch()} method was last called (or time the
session was created). A UNIX timestamp as returned by
L{IReactorTime.seconds()}.
@type lastModified L{float}
"""

sessionTimeout = 900
Expand All @@ -701,11 +712,14 @@ class Session(components.Componentized):
def __init__(self, site, uid, reactor=None):
"""
Initialize a session with a unique ID for that session.
@param reactor: L{IReactorTime} used to schedule expiration of the
session. If C{None}, the reactor associated with I{site} is used.
"""
components.Componentized.__init__(self)
super().__init__()

if reactor is None:
from twisted.internet import reactor
reactor = site.reactor
self._reactor = reactor

self.site = site
Expand Down Expand Up @@ -743,7 +757,7 @@ def expire(self):

def touch(self):
"""
Notify session modification.
Mark the session as modified, which resets expiration timer.
"""
self.lastModified = self._reactor.seconds()
if self._expireCall is not None:
Expand All @@ -758,13 +772,24 @@ class Site(http.HTTPFactory):
"""
A web site: manage log, sessions, and resources.
@ivar counter: increment value used for generating unique sessions ID.
@ivar requestFactory: A factory which is called with (channel)
and creates L{Request} instances. Default to L{Request}.
@ivar displayTracebacks: If set, unhandled exceptions raised during
rendering are returned to the client as HTML. Default to C{False}.
@ivar sessionFactory: factory for sessions objects. Default to L{Session}.
@ivar sessionCheckTime: Deprecated. See L{Session.sessionTimeout} instead.
@ivar sessions: Mapping of session IDs to objects returned by
C{sessionFactory}.
@type sessions: L{dict} mapping L{bytes} to L{Session} given the default
C{sessionFactory}
@ivar counter: The number of sessions that have been generated.
@type counter: L{int}
@ivar sessionCheckTime: Deprecated and unused. See
L{Session.sessionTimeout} instead.
"""

counter = 0
Expand All @@ -785,7 +810,7 @@ def __init__(self, resource, requestFactory=None, *args, **kwargs):
@see: L{twisted.web.http.HTTPFactory.__init__}
"""
http.HTTPFactory.__init__(self, *args, **kwargs)
super().__init__(*args, **kwargs)
self.sessions = {}
self.resource = resource
if requestFactory is not None:
Expand Down Expand Up @@ -832,7 +857,7 @@ def buildProtocol(self, addr):
"""
Generate a channel attached to this site.
"""
channel = http.HTTPFactory.buildProtocol(self, addr)
channel = super().buildProtocol(addr)
channel.requestFactory = self.requestFactory
channel.site = self
return channel
Expand Down
3 changes: 2 additions & 1 deletion src/twisted/web/test/requesthelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from twisted.internet.defer import Deferred
from twisted.internet.address import IPv4Address, IPv6Address
from twisted.internet.interfaces import ISSLTransport, IAddress
from twisted.internet.task import Clock

from twisted.trial import unittest

Expand Down Expand Up @@ -233,7 +234,7 @@ def __init__(self, postpath, session=None, client=None):
self.postpath = postpath
self.prepath = []
self.session = None
self.protoSession = session or Session(0, self)
self.protoSession = session or Session(site=None, uid=b"0", reactor=Clock())
self.args = {}
self.requestHeaders = Headers()
self.responseHeaders = Headers()
Expand Down
3 changes: 1 addition & 2 deletions src/twisted/web/test/test_cgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,7 @@ def test_urlParameters(self):
"""
cgiFilename = self.writeCGI(URL_PARAMETER_CGI)
portnum = self.startServer(cgiFilename)
url = "http://localhost:%d/cgi?param=1234" % (portnum,)
url = url.encode("ascii")
url = b"http://localhost:%d/cgi?param=1234" % (portnum,)
agent = client.Agent(reactor)
d = agent.request(b"GET", url)
d.addCallback(client.readBody)
Expand Down
34 changes: 23 additions & 11 deletions src/twisted/web/test/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from twisted.python import reflect, failure
from twisted.python.filepath import FilePath
from twisted.trial import unittest
from twisted.internet import reactor, interfaces
from twisted.internet import interfaces
from twisted.internet.address import IPv4Address, IPv6Address
from twisted.internet.task import Clock
from twisted.web import server, resource
Expand Down Expand Up @@ -214,17 +214,29 @@ def setUp(self):
"""
self.clock = Clock()
self.uid = b"unique"
self.site = server.Site(resource.Resource())
self.session = server.Session(self.site, self.uid, self.clock)
self.site = server.Site(resource.Resource(), reactor=self.clock)
self.session = server.Session(self.site, self.uid)
self.site.sessions[self.uid] = self.session

def test_defaultReactor(self):
"""
If not value is passed to L{server.Session.__init__}, the global
reactor is used.
If no value is passed to L{server.Session.__init__}, the reactor
associated with the site is used.
"""
session = server.Session(server.Site(resource.Resource()), b"123")
self.assertIdentical(session._reactor, reactor)
site = server.Site(resource.Resource(), reactor=Clock())
session = server.Session(site, b"123")
self.assertIdentical(session._reactor, site.reactor)

def test_explicitReactor(self):
"""
L{Session} accepts the reactor to use as a parameter.
"""
site = server.Site(resource.Resource())
otherReactor = Clock()

session = server.Session(site, b"123", reactor=otherReactor)

self.assertIdentical(session._reactor, otherReactor)

def test_startCheckingExpiration(self):
"""
Expand Down Expand Up @@ -761,7 +773,7 @@ def test_retrieveExistingSession(self):
request = server.Request(d, 1)
request.site = site
request.sitepath = []
mySession = server.Session(b"special-id", site)
mySession = server.Session(site, b"special-id")
site.sessions[mySession.uid] = mySession
request.received_cookies[b"TWISTED_SESSION"] = mySession.uid
self.assertIs(request.getSession(), mySession)
Expand Down Expand Up @@ -1827,11 +1839,11 @@ class ExplicitHTTPFactoryReactor(unittest.TestCase):
def test_explicitReactor(self):
"""
L{http.HTTPFactory.__init__} accepts a reactor argument which is set on
L{http.HTTPFactory._reactor}.
L{http.HTTPFactory.reactor}.
"""
reactor = "I am a reactor!"
factory = http.HTTPFactory(reactor=reactor)
self.assertIs(factory._reactor, reactor)
self.assertIs(factory.reactor, reactor)

def test_defaultReactor(self):
"""
Expand All @@ -1841,4 +1853,4 @@ def test_defaultReactor(self):
from twisted.internet import reactor

factory = http.HTTPFactory()
self.assertIs(factory._reactor, reactor)
self.assertIs(factory.reactor, reactor)
2 changes: 0 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
minversion=3.21.4
requires=
virtualenv>=20.4.2
tox-wheel>=0.6.0
skip_missing_interpreters=True
envlist=lint, mypy,
apidocs, narrativedocs, newsfragment,
Expand All @@ -35,7 +34,6 @@ sources = setup.py src/ docs/conch/examples docs/mail/examples docs/names/exampl
; docs/core/examples

[testenv]
wheel = True
;; dependencies managed by extras in setup.cfg
extras =
; The "nodeps" build still depends on PyHamcrest.
Expand Down

0 comments on commit 9f0d979

Please sign in to comment.