Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/trunk' into 9374-ilyaskriblovs…
Browse files Browse the repository at this point in the history
…ky-circular-refs-in-tls
  • Loading branch information
IlyaSkriblovsky committed Mar 25, 2018
2 parents b0433dd + 3a065fe commit a55a8b0
Show file tree
Hide file tree
Showing 20 changed files with 121 additions and 112 deletions.
2 changes: 2 additions & 0 deletions docs/core/howto/threading.rst
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ When we run some code, we often want to know what its result was. For this, Twi

To get a result from some blocking code back into the reactor thread, we can use :api:`twisted.internet.threads.deferToThread <deferToThread>` to execute it instead of callFromThread.

::

from __future__ import print_function
from twisted.internet import reactor, threads

Expand Down
2 changes: 1 addition & 1 deletion src/twisted/internet/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def resolveHostName(resolutionReceiver, hostName, portNumber=0,
practice, this means an iterable containing
L{twisted.internet.address.IPv4Address},
L{twisted.internet.address.IPv6Address}, both, or neither.
@type addressTypes: L{collections.Iterable} of L{type}
@type addressTypes: L{collections.abc.Iterable} of L{type}
@param transportSemantics: A string describing the semantics of the
transport; either C{'TCP'} for stream-oriented transports or
Expand Down
1 change: 1 addition & 0 deletions src/twisted/newsfragments/7704.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.web.http.Request.getClientIP now returns the host part of the client's address when connected over IPv6.
1 change: 1 addition & 0 deletions src/twisted/newsfragments/8241.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.web.wsgi.WSGIResource no longer raises an exception when a client connects over IPv6.
Empty file.
Empty file.
Empty file.
Empty file.
7 changes: 6 additions & 1 deletion src/twisted/python/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,10 @@ def _bytesRepr(bytestring):
else:
_tokenize = tokenize.generate_tokens

try:
from collections.abc import Sequence
except ImportError:
from collections import Sequence


__all__ = [
Expand Down Expand Up @@ -868,5 +872,6 @@ def _bytesRepr(bytestring):
"intern",
"unichr",
"raw_input",
"_tokenize"
"_tokenize",
"Sequence",
]
3 changes: 1 addition & 2 deletions src/twisted/test/proto_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@

from socket import AF_INET, AF_INET6
from io import BytesIO
from collections import Sequence

from zope.interface import implementer, implementedBy
from zope.interface.verify import verifyClass

from twisted.python import failure
from twisted.python.compat import unicode, intToBytes
from twisted.python.compat import unicode, intToBytes, Sequence
from twisted.internet.defer import Deferred
from twisted.internet.interfaces import (
ITransport, IConsumer, IPushProducer, IConnector,
Expand Down
58 changes: 37 additions & 21 deletions src/twisted/test/test_threadpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@

from __future__ import division, absolute_import

import pickle, time, weakref, gc, threading
import pickle
import time
import weakref
import gc
import threading

from twisted.python.compat import range

from twisted.trial import unittest
from twisted.python import threadpool, threadable, failure, context
from twisted._threads import Team, createMemoryWorker

#
# See the end of this module for the remainder of the imports.
#


class Synchronization(object):
failures = 0
Expand All @@ -36,10 +38,9 @@ def run(self):
# holding the lock.
if self.lock.acquire(False):
if not len(self.runs) % 5:
time.sleep(0.0002) # Constant selected based on
# empirical data to maximize the
# chance of a quick failure if this
# code is broken.
# Constant selected based on empirical data to maximize the
# chance of a quick failure if this code is broken.
time.sleep(0.0002)
self.lock.release()
else:
self.failures += 1
Expand All @@ -54,6 +55,9 @@ def run(self):
self.lock.release()

synchronized = ["run"]



threadable.synchronize(Synchronization)


Expand All @@ -67,7 +71,7 @@ def getTimeout(self):
"""
Return number of seconds to wait before giving up.
"""
return 5 # Really should be order of magnitude less
return 5 # Really should be order of magnitude less


def _waitForLock(self, lock):
Expand Down Expand Up @@ -135,9 +139,11 @@ def test_threadCreationArguments(self):
# Here's our function
def worker(arg):
pass

# weakref needs an object subclass
class Dumb(object):
pass

# And here's the unique object
unique = Dumb()

Expand Down Expand Up @@ -173,7 +179,7 @@ def test_threadCreationArgumentsCallInThreadWithCallback(self):
self.assertEqual(tp.threads, [])

# this holds references obtained in onResult
refdict = {} # name -> ref value
refdict = {} # name -> ref value

onResultWait = threading.Event()
onResultDone = threading.Event()
Expand All @@ -182,6 +188,9 @@ def test_threadCreationArgumentsCallInThreadWithCallback(self):

# result callback
def onResult(success, result):
# Spin the GC, which should now delete worker and unique if it's
# not held on to by callInThreadWithCallback after it is complete
gc.collect()
onResultWait.wait(self.getTimeout())
refdict['workerRef'] = workerRef()
refdict['uniqueRef'] = uniqueRef()
Expand Down Expand Up @@ -227,6 +236,9 @@ class Dumb(object):
self.assertIsNone(onResultRef())
self.assertIsNone(resultRef[0]())

# The callback shouldn't have been able to resolve the references.
self.assertEqual(list(refdict.values()), [None, None])


def test_persistence(self):
"""
Expand Down Expand Up @@ -269,8 +281,9 @@ def _threadpoolTest(self, method):

self._waitForLock(waiting)

self.assertFalse(actor.failures, "run() re-entered %d times" %
(actor.failures,))
self.assertFalse(
actor.failures,
"run() re-entered {} times".format(actor.failures))


def test_callInThread(self):
Expand Down Expand Up @@ -385,7 +398,7 @@ def onResult(success, result):
raise NewError()

tp = threadpool.ThreadPool(0, 1)
tp.callInThreadWithCallback(onResult, lambda : None)
tp.callInThreadWithCallback(onResult, lambda: None)
tp.callInThread(waiter.release)
tp.start()

Expand Down Expand Up @@ -471,7 +484,7 @@ def test_existingWork(self):
waiter.acquire()

tp = threadpool.ThreadPool(0, 1)
tp.callInThread(waiter.release) # before start()
tp.callInThread(waiter.release) # Before start()
tp.start()

try:
Expand All @@ -489,12 +502,12 @@ def test_workerStateTransition(self):
pool.start()
self.addCleanup(pool.stop)

# sanity check
# Sanity check
self.assertEqual(pool.workers, 0)
self.assertEqual(len(pool.waiters), 0)
self.assertEqual(len(pool.working), 0)

# fire up a worker and give it some 'work'
# Fire up a worker and give it some 'work'
threadWorking = threading.Event()
threadFinish = threading.Event()

Expand All @@ -508,12 +521,12 @@ def _thread():
self.assertEqual(len(pool.waiters), 0)
self.assertEqual(len(pool.working), 1)

# finish work, and spin until state changes
# Finish work, and spin until state changes
threadFinish.set()
while not len(pool.waiters):
time.sleep(0.0005)

# make sure state changed correctly
# Make sure state changed correctly
self.assertEqual(len(pool.waiters), 1)
self.assertEqual(len(pool.working), 0)

Expand All @@ -525,9 +538,11 @@ def setUp(self):
self.threadpool = threadpool.ThreadPool(0, 10)
self.event = threading.Event()
self.threadpool.start()

def done():
self.threadpool.stop()
del self.threadpool

self.addCleanup(done)


Expand Down Expand Up @@ -649,8 +664,8 @@ def respectLimit():
# twisted.threads._pool, which is unfortunately bound up
# with lots of actual-threading stuff.
stats = team.statistics()
if (stats.busyWorkerCount + stats.idleWorkerCount
>= currentLimit()):
if ((stats.busyWorkerCount +
stats.idleWorkerCount) >= currentLimit()):
return None
return self._newWorker()
team = Team(coordinator=self._coordinator,
Expand Down Expand Up @@ -690,9 +705,11 @@ def __init__(self, testCase, *args, **kwargs):
"""
coordinator, self.performCoordination = createMemoryWorker()
self.workers = []

def newWorker():
self.workers.append(createMemoryWorker())
return self.workers[-1][0]

self.threadpool = MemoryPool(coordinator, testCase.fail, newWorker,
*args, **kwargs)

Expand Down Expand Up @@ -745,4 +762,3 @@ def test_tooMuchWorkBeforeStarting(self):
helper.threadpool.start()
helper.performAllCoordination()
self.assertEqual(len(helper.workers), helper.threadpool.max)

4 changes: 2 additions & 2 deletions src/twisted/web/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
'RedirectWithNoLocation',
]

from collections import Sequence

from twisted.web._responses import RESPONSES
from twisted.python.compat import unicode, nativeString, intToBytes
from twisted.python.compat import unicode, nativeString, intToBytes, Sequence



def _codeToMessage(code):
Expand Down
18 changes: 1 addition & 17 deletions src/twisted/web/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,7 @@ def getClientIP(self):
@returns: the client IP address
@rtype: C{str}
"""
if isinstance(self.client, address.IPv4Address):
if isinstance(self.client, (address.IPv4Address, address.IPv6Address)):
return self.client.host
else:
return None
Expand Down Expand Up @@ -1466,17 +1466,6 @@ def getPassword(self):
return self.password


def getClient(self):
"""
Get the client's IP address, if it has one. No attempt is made to
resolve the address to a hostname.
@return: The same value as C{getClientIP}.
@rtype: L{bytes}
"""
return self.getClientIP()


def connectionLost(self, reason):
"""
There is no longer a connection for this request to respond over.
Expand Down Expand Up @@ -1550,11 +1539,6 @@ def __hash__(self):



Request.getClient = deprecated(
Version("Twisted", 15, 0, 0),
"Twisted Names to resolve hostnames")(Request.getClient)


Request.noLongerQueued = deprecated(
Version("Twisted", 16, 3, 0))(Request.noLongerQueued)

Expand Down
13 changes: 0 additions & 13 deletions src/twisted/web/iweb.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,6 @@ def getClientIP():
"""


def getClient():
"""
Return the hostname of the IP address of the client who submitted this
request, if possible.
This method is B{deprecated}. See L{getClientIP} instead.
@rtype: L{None} or L{str}
@return: The canonical hostname of the client, as determined by
performing a name lookup on the IP address of the client.
"""


def getUser():
"""
Return the HTTP user sent with this request, if any.
Expand Down
1 change: 1 addition & 0 deletions src/twisted/web/newsfragments/9395.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
twisted.web.iweb.IRequest.getClient and its implementations (deprecated in #2552) have been removed.
27 changes: 7 additions & 20 deletions src/twisted/web/test/requesthelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
from zope.interface import implementer

from twisted.python.compat import intToBytes
from twisted.python.deprecate import deprecated
from incremental import Version
from twisted.internet.defer import Deferred
from twisted.internet.address import IPv4Address
from twisted.internet.interfaces import ISSLTransport
Expand All @@ -31,12 +29,15 @@ class TCP:
port = 80
disconnected = False

def __init__(self):
def __init__(self, peer=None):
if peer is None:
peer = IPv4Address("TCP", '192.168.1.1', 12344)
self._peer = peer
self.written = BytesIO()
self.producers = []

def getPeer(self):
return IPv4Address("TCP", '192.168.1.1', 12344)
return self._peer

def write(self, data):
if not isinstance(data, bytes):
Expand Down Expand Up @@ -66,8 +67,8 @@ class SSL(TCP):

site = Site(Resource())

def __init__(self):
self.transport = self.TCP()
def __init__(self, peer=None):
self.transport = self.TCP(peer)


def requestDone(self, request):
Expand Down Expand Up @@ -357,16 +358,6 @@ def setHost(self, host, port, ssl=0):
self.requestHeaders.addRawHeader(b"host", hostHeader)


def getClient(self):
"""
Get the client's IP address, if it has one.
@return: The same value as C{getClientIP}.
@rtype: L{bytes}
"""
return self.getClientIP()


def redirect(self, url):
"""
Utility function that does a redirect.
Expand All @@ -375,7 +366,3 @@ def redirect(self, url):
"""
self.setResponseCode(FOUND)
self.setHeader(b"location", url)

DummyRequest.getClient = deprecated(
Version("Twisted", 15, 0, 0),
"Twisted Names to resolve hostnames")(DummyRequest.getClient)
Loading

0 comments on commit a55a8b0

Please sign in to comment.